pdrc 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ad88a28463c4f3146a5f822594932fb41baba97fa5e4e3f9c2894b40ba7d65b8
4
+ data.tar.gz: c0861d9d00e1e109beee2faf2b0bc029228a1326c6247efdb5a3a618caf00b80
5
+ SHA512:
6
+ metadata.gz: 69fa2eae94c04370bacee17cd2e0d2011c099569e9c11cc705d43d0a40f03d7b19771666608a4f04b41467fcefb036cc2fee1f16bb8a2e1cea5024450fe2f12a
7
+ data.tar.gz: a42d91d8517b08e8bce03c4415e2e47c11c1d808d0fb134fb6604cbeac1950bdcc3bb317625f2a0f7e3c6a6b771f31d6c22ef46a3f11dac2bbfb94c62ffcf0e4
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,49 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # rdoc generated
5
+ rdoc
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # bundler
12
+ .bundle
13
+
14
+ # jeweler generated
15
+ pkg
16
+
17
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
18
+ #
19
+ # * Create a file at ~/.gitignore
20
+ # * Include files you want ignored
21
+ # * Run: git config --global core.excludesfile ~/.gitignore
22
+ #
23
+ # After doing this, these files will be ignored in all your git projects,
24
+ # saving you from having to 'pollute' every project you touch with them
25
+ #
26
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
27
+ #
28
+ # For MacOS:
29
+ #
30
+ .DS_Store
31
+ #
32
+ # For TextMate
33
+ #*.tmproj
34
+ #tmtags
35
+ #
36
+ # For emacs:
37
+ #*~
38
+ #\#*
39
+ #.\#*
40
+ #
41
+ # For vim:
42
+ #*.swp
43
+
44
+ bin
45
+ cache
46
+ gems
47
+ specifications
48
+ Gemfile.lock
49
+ .rvmrc
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ pdrc
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.4.3
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ sudo: false
3
+ cache: bundler
4
+ before_install:
5
+ - gem install bundler # -v 1.7.14 if a specific version is needed
6
+ rvm:
7
+ - 2.0.0
8
+ - 2.1.5
9
+ - 2.2.2
10
+ - 2.3.3
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ ## [Unreleased][unreleased]
2
+
3
+ ## [1.0.0] - 2018-07-21
4
+ - Ported amro/gibbon over to use the Pagerduty API, including:
5
+ - Using an Authorization header instead of a token parameter
6
+ - Streamlining all datacenter-related URL componentry
7
+ - Removing Export API functionality
8
+ - Updating README to reflect new status
9
+
10
+ [unreleased]: https://github.com/ltw/pdrc/compare/v1.0.0...HEAD
11
+ [1.0.0]: https://github.com/ltw/pdrc/compare/...v1.0.0
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+
3
+ platforms :rbx do
4
+ gem 'rubysl', '~> 2.2.0'
5
+ gem 'rubinius-developer_tools'
6
+ end
7
+
8
+ group :development, :test do
9
+ gem 'webmock', '~>1.24.0'
10
+ end
11
+
12
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010-2017 Amro Mousa & Lucas Willett
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,213 @@
1
+ # pdrc
2
+
3
+ pdrc is an API wrapper for Pagerduty's [REST API v2](https://v2.developer.pagerduty.com/docs/rest-api), based off amro's great MailChimp client [Gibbon](https://github.com/amro/gibbon).
4
+
5
+ [![Build Status](https://secure.travis-ci.org/ltw/pdrc.svg)](http://travis-ci.org/ltw/pdrc)
6
+
7
+ ## Important Notes
8
+
9
+ Please read Pagerduty's [Overview documentation](https://v2.developer.pagerduty.com/docs/rest-api).
10
+
11
+ pdrc returns a `PDRC::Response` instead of the response body directly. `PDRC::Response` exposes the parsed response `body` and `headers`.
12
+
13
+ ## Installation
14
+
15
+ $ gem install pdrc
16
+
17
+ ## Requirements
18
+
19
+ A Pagerduty account and a v2 API key. Only administrators can generate API keys.
20
+
21
+ ## Usage
22
+
23
+ First, create a *one-time use instance* of `PDRC::Request`:
24
+
25
+ ```ruby
26
+ pdrc = PDRC::Request.new(api_key: "your_api_key")
27
+ ```
28
+
29
+ ***Note*** Only reuse instances of pdrc after terminating a call with a verb, which makes a request. Requests are light weight objects that update an internal path based on your call chain. When you terminate a call chain with a verb, a request instance makes a request and resets the path.
30
+
31
+ You can set an individual request's `timeout` and `open_timeout` like this:
32
+
33
+ ```ruby
34
+ pdrc.timeout = 30
35
+ pdrc.open_timeout = 30
36
+ ```
37
+
38
+ You can read about `timeout` and `open_timeout` in the [Net::HTTP](https://ruby-doc.org/stdlib-2.3.3/libdoc/net/http/rdoc/Net/HTTP.html) doc.
39
+
40
+ Now you can make requests using the resources defined in [Pagerduty's docs](https://v2.developer.pagerduty.com/v2/page/api-reference). Resource IDs are specified inline and a `CRUD` (`create`, `retrieve`, `update`, or `delete`) verb initiates the request.
41
+
42
+ You can specify `headers`, `params`, and `body` when calling a `CRUD` method. For example:
43
+
44
+ ```ruby
45
+ pdrc.teams.retrieve(headers: {"SomeHeader": "SomeHeaderValue"}, params: {"query_param": "query_param_value"})
46
+ ```
47
+
48
+ Of course, `body` is only supported on `create` and `update` calls. Those map to HTTP `POST`, `PATCH`, and `PUT` verbs respectively.
49
+
50
+ You can set `api_key`, `timeout`, `open_timeout`, `faraday_adapter`, `proxy`, `symbolize_keys`, `logger`, and `debug` globally:
51
+
52
+ ```ruby
53
+ PDRC::Request.api_key = "your_api_key"
54
+ PDRC::Request.timeout = 15
55
+ PDRC::Request.open_timeout = 15
56
+ PDRC::Request.symbolize_keys = true
57
+ PDRC::Request.debug = false
58
+ ```
59
+
60
+ For example, you could set the values above in an `initializer` file in your `Rails` app (e.g. your\_app/config/initializers/pdrc.rb).
61
+
62
+ Assuming you've set an `api_key` on PDRC, you can conveniently make API calls on the class itself:
63
+
64
+ ```ruby
65
+ PDRC::Request.teams.retrieve
66
+ ```
67
+
68
+ You can also set the environment variable `PAGERDUTY_API_KEY` and PDRC will use it when you create an instance:
69
+
70
+ ```ruby
71
+ pdrc = PDRC::Request.new
72
+ ```
73
+
74
+ ***Note*** Substitute an underscore if a resource name contains a hyphen.
75
+
76
+ Pass `symbolize_keys: true` to use symbols (instead of strings) as hash keys in API responses.
77
+
78
+ ```ruby
79
+ pdrc = PDRC::Request.new(api_key: "your_api_key", symbolize_keys: true)
80
+ ```
81
+
82
+ Pagerduty's [REST API documentation](https://v2.developer.pagerduty.com/v2/page/api-reference) is a list of available resources.
83
+
84
+ ## Debug Logging
85
+
86
+ Pass `debug: true` to enable debug logging to STDOUT.
87
+
88
+ ```ruby
89
+ pdrc = PDRC::Request.new(api_key: "your_api_key", debug: true)
90
+ ```
91
+
92
+ ### Custom logger
93
+
94
+ Ruby `Logger.new` is used by default, but it can be overrided using:
95
+
96
+ ```ruby
97
+ pdrc = PDRC::Request.new(api_key: "your_api_key", debug: true, logger: MyLogger.new)
98
+ ```
99
+
100
+ Logger can be also set by globally:
101
+
102
+ ```ruby
103
+ PDRC::Request.logger = MyLogger.new
104
+ ```
105
+
106
+ ## Examples
107
+
108
+ ### Teams
109
+
110
+ Fetch all teams:
111
+
112
+ ```ruby
113
+ pdrc.teams.retrieve
114
+ ```
115
+
116
+ Retrieving a specific team looks like:
117
+
118
+ ```ruby
119
+ pdrc.teams(team_id).retrieve
120
+ ```
121
+
122
+ Create a team:
123
+
124
+ ```ruby
125
+ pdrc.teams.create(body: {team: { type: "team", name: "Engineering", description: "The engineering team"}})
126
+ ```
127
+
128
+ You can also delete a team:
129
+
130
+ ```ruby
131
+ pdrc.teams(team_id).delete
132
+ ```
133
+
134
+ ### Schedules
135
+
136
+ Get all schedules:
137
+
138
+ ```ruby
139
+ pdrc.schedules.retrieve(params: {"query": "Primary"})
140
+ ```
141
+
142
+ By default the Pagerduty API returns 25 results. To set the count to 50 (Note: it cannot exceed 100):
143
+
144
+ ```ruby
145
+ pdrc.schedules.retrieve(params: {"limit": "50"})
146
+ ```
147
+
148
+ And to retrieve the next 50 schedules:
149
+
150
+ ```ruby
151
+ pdrc.schedules.retrieve(params: {"limit": "50", "offset": "50"})
152
+ ```
153
+
154
+ And to retrieve only the schedules with the title containing "Primary":
155
+
156
+ ```ruby
157
+ pdrc.schedules.retrieve(params: {"limit": "50", "offset": "50", "query": "Primary"})
158
+ ```
159
+
160
+ Get a list of overrides for a schedule:
161
+
162
+ ```ruby
163
+ pdrc.schedules(schedule_id).overrides.retrieve
164
+ ```
165
+
166
+ Or to list users on-call for a schedule:
167
+
168
+ ```ruby
169
+ pdrc.schedules(schedule_id).users.retrieve
170
+ ```
171
+
172
+ To narrow the range of on-call users down to a specific date range:
173
+
174
+ ```ruby
175
+ pdrc.schedules(schedule_id).users.retrieve(params: {"since": "2018-06-01T00:00:00Z", "until": "2018-09-01T00:00:00Z"})
176
+ ```
177
+
178
+ ### Error handling
179
+
180
+ PDRC raises an error when the API returns an error.
181
+
182
+ `PDRC::PagerdutyError` has the following attributes: `title`, `detail`, `body`, `raw_body`, `status_code`. Some or all of these may not be
183
+ available depending on the nature of the error. For example:
184
+
185
+ ```ruby
186
+ begin
187
+ pdrc.teams(team_id).create(body: body)
188
+ rescue PDRC::PagerdutyError => e
189
+ puts "Houston, we have a problem: #{e.message} - #{e.raw_body}"
190
+ end
191
+ ```
192
+
193
+ ### Other
194
+
195
+ You can set an optional proxy url like this (or with an environment variable MAILCHIMP_PROXY):
196
+
197
+ ```ruby
198
+ pdrc.proxy = 'http://your_proxy.com:80'
199
+ ```
200
+
201
+ You can set a different [Faraday adapter](https://github.com/lostisland/faraday) during initialization:
202
+
203
+ ```ruby
204
+ pdrc = PDRC::Request.new(api_key: "your_api_key", faraday_adapter: :net_http)
205
+ ```
206
+
207
+ ## Thanks
208
+
209
+ Thanks to everyone who has [contributed](https://github.com/amro/gibbon/contributors) to Gibbon's development which has been so integral to PDRC's development.
210
+
211
+ ## Copyright
212
+
213
+ * Copyright (c) 2010-2018 Amro Mousa & Lucas Willett. See LICENSE.txt for details.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubygems/specification'
4
+ require 'bundler/gem_tasks'
5
+
6
+ task :default => :spec
7
+ desc "Run specs"
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.pattern = FileList['spec/**/*_spec.rb']
10
+ t.rspec_opts = %w(-fd --color)
11
+ end
data/lib/pdrc.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'faraday'
2
+ require 'multi_json'
3
+ require 'cgi'
4
+ require 'logger'
5
+
6
+ require 'pdrc/pdrc_error'
7
+ require 'pdrc/pagerduty_error'
8
+ require 'pdrc/request'
9
+ require 'pdrc/api_request'
10
+ require 'pdrc/response'
11
+
12
+ module PDRC
13
+ end
@@ -0,0 +1,189 @@
1
+ module PDRC
2
+ class APIRequest
3
+ def initialize(builder: nil)
4
+ @request_builder = builder
5
+ end
6
+
7
+ def post(params: nil, headers: nil, body: nil)
8
+ validate_api_key
9
+
10
+ begin
11
+ response = self.rest_client.post do |request|
12
+ configure_request(request: request, params: params, headers: headers, body: MultiJson.dump(body))
13
+ end
14
+ parse_response(response)
15
+ rescue => e
16
+ handle_error(e)
17
+ end
18
+ end
19
+
20
+ def patch(params: nil, headers: nil, body: nil)
21
+ validate_api_key
22
+
23
+ begin
24
+ response = self.rest_client.patch do |request|
25
+ configure_request(request: request, params: params, headers: headers, body: MultiJson.dump(body))
26
+ end
27
+ parse_response(response)
28
+ rescue => e
29
+ handle_error(e)
30
+ end
31
+ end
32
+
33
+ def put(params: nil, headers: nil, body: nil)
34
+ validate_api_key
35
+
36
+ begin
37
+ response = self.rest_client.put do |request|
38
+ configure_request(request: request, params: params, headers: headers, body: MultiJson.dump(body))
39
+ end
40
+ parse_response(response)
41
+ rescue => e
42
+ handle_error(e)
43
+ end
44
+ end
45
+
46
+ def get(params: nil, headers: nil)
47
+ validate_api_key
48
+
49
+ begin
50
+ response = self.rest_client.get do |request|
51
+ configure_request(request: request, params: params, headers: headers)
52
+ end
53
+ parse_response(response)
54
+ rescue => e
55
+ handle_error(e)
56
+ end
57
+ end
58
+
59
+ def delete(params: nil, headers: nil)
60
+ validate_api_key
61
+
62
+ begin
63
+ response = self.rest_client.delete do |request|
64
+ configure_request(request: request, params: params, headers: headers)
65
+ end
66
+ parse_response(response)
67
+ rescue => e
68
+ handle_error(e)
69
+ end
70
+ end
71
+
72
+ protected
73
+
74
+ # Convenience accessors
75
+
76
+ def api_key
77
+ @request_builder.api_key
78
+ end
79
+
80
+ def api_endpoint
81
+ @request_builder.api_endpoint
82
+ end
83
+
84
+ def timeout
85
+ @request_builder.timeout
86
+ end
87
+
88
+ def open_timeout
89
+ @request_builder.open_timeout
90
+ end
91
+
92
+ def proxy
93
+ @request_builder.proxy
94
+ end
95
+
96
+ def adapter
97
+ @request_builder.faraday_adapter
98
+ end
99
+
100
+ def symbolize_keys
101
+ @request_builder.symbolize_keys
102
+ end
103
+
104
+ # Helpers
105
+
106
+ def handle_error(error)
107
+ error_params = {}
108
+
109
+ begin
110
+ if error.is_a?(Faraday::Error::ClientError) && error.response
111
+ error_params[:status_code] = error.response[:status]
112
+ error_params[:raw_body] = error.response[:body]
113
+
114
+ parsed_response = MultiJson.load(error.response[:body], symbolize_keys: symbolize_keys)
115
+
116
+ if parsed_response
117
+ error_params[:body] = parsed_response
118
+
119
+ title_key = symbolize_keys ? :title : "title"
120
+ detail_key = symbolize_keys ? :detail : "detail"
121
+
122
+ error_params[:title] = parsed_response[title_key] if parsed_response[title_key]
123
+ error_params[:detail] = parsed_response[detail_key] if parsed_response[detail_key]
124
+ end
125
+
126
+ end
127
+ rescue MultiJson::ParseError
128
+ end
129
+
130
+ error_to_raise = PagerdutyError.new(error.message, error_params)
131
+
132
+ raise error_to_raise
133
+ end
134
+
135
+ def configure_request(request: nil, params: nil, headers: nil, body: nil)
136
+ if request
137
+ request.params.merge!(params) if params
138
+ request.headers['Content-Type'] = 'application/json'
139
+ request.headers['Accept'] = 'application/vnd.pagerduty+json;version=2'
140
+ request.headers.merge!(headers) if headers
141
+ request.body = body if body
142
+ request.options.timeout = self.timeout
143
+ request.options.open_timeout = self.open_timeout
144
+ end
145
+ end
146
+
147
+ def rest_client
148
+ client = Faraday.new(self.api_url, proxy: self.proxy, ssl: { version: "TLSv1_2" }) do |faraday|
149
+ faraday.response :raise_error
150
+ faraday.adapter adapter
151
+ if @request_builder.debug
152
+ faraday.response :logger, @request_builder.logger, bodies: true
153
+ end
154
+ end
155
+ client.authorization(:Token, token: self.api_key)
156
+ client
157
+ end
158
+
159
+ def parse_response(response)
160
+ parsed_response = nil
161
+
162
+ if response.body && !response.body.empty?
163
+ begin
164
+ headers = response.headers
165
+ body = MultiJson.load(response.body, symbolize_keys: symbolize_keys)
166
+ parsed_response = Response.new(headers: headers, body: body)
167
+ rescue MultiJson::ParseError
168
+ error_params = { title: "UNPARSEABLE_RESPONSE", status_code: 500 }
169
+ error = PagerdutyError.new("Unparseable response: #{response.body}", error_params)
170
+ raise error
171
+ end
172
+ end
173
+
174
+ parsed_response
175
+ end
176
+
177
+ def validate_api_key
178
+ raise PDRC::PDRCError, "You must set an api_key prior to making a call" unless self.api_key
179
+ end
180
+
181
+ def api_url
182
+ base_api_url + @request_builder.path
183
+ end
184
+
185
+ def base_api_url
186
+ "https://api.pagerduty.com/"
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,29 @@
1
+ module PDRC
2
+ class PagerdutyError < StandardError
3
+ attr_reader :title, :detail, :body, :raw_body, :status_code
4
+
5
+ def initialize(message = "", params = {})
6
+ @title = params[:title]
7
+ @detail = params[:detail]
8
+ @body = params[:body]
9
+ @raw_body = params[:raw_body]
10
+ @status_code = params[:status_code]
11
+
12
+ super(message)
13
+ end
14
+
15
+ def to_s
16
+ super + " " + instance_variables_to_s
17
+ end
18
+
19
+ private
20
+
21
+ def instance_variables_to_s
22
+ [:title, :detail, :body, :raw_body, :status_code].map do |attr|
23
+ attr_value = send(attr)
24
+
25
+ "@#{attr}=#{attr_value.inspect}"
26
+ end.join(", ")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module PDRC
2
+ class PDRCError < StandardError; end
3
+ end
@@ -0,0 +1,87 @@
1
+ module PDRC
2
+ class Request
3
+ attr_accessor :api_key, :api_endpoint, :timeout, :open_timeout, :proxy, :faraday_adapter, :symbolize_keys, :debug, :logger
4
+
5
+ DEFAULT_TIMEOUT = 60
6
+ DEFAULT_OPEN_TIMEOUT = 60
7
+
8
+ def initialize(api_key: nil, api_endpoint: nil, timeout: nil, open_timeout: nil, proxy: nil, faraday_adapter: nil, symbolize_keys: false, debug: false, logger: nil)
9
+ @path_parts = []
10
+ @api_key = api_key || self.class.api_key || ENV['PAGERDUTY_API_KEY']
11
+ @api_key = @api_key.strip if @api_key
12
+ @api_endpoint = api_endpoint || self.class.api_endpoint
13
+ @timeout = timeout || self.class.timeout || DEFAULT_TIMEOUT
14
+ @open_timeout = open_timeout || self.class.open_timeout || DEFAULT_OPEN_TIMEOUT
15
+ @proxy = proxy || self.class.proxy || ENV['PAGERDUTY_PROXY']
16
+ @faraday_adapter = faraday_adapter || Faraday.default_adapter
17
+ @symbolize_keys = symbolize_keys || self.class.symbolize_keys || false
18
+ @debug = debug || self.class.debug || false
19
+ @logger = logger || self.class.logger || ::Logger.new(STDOUT)
20
+ end
21
+
22
+ def method_missing(method, *args)
23
+ @path_parts << method.to_s.downcase
24
+ @path_parts << args if args.length > 0
25
+ @path_parts.flatten!
26
+ self
27
+ end
28
+
29
+ def respond_to_missing?(method_name, include_private = false)
30
+ true
31
+ end
32
+
33
+ def send(*args)
34
+ if args.length == 0
35
+ method_missing(:send, args)
36
+ else
37
+ __send__(*args)
38
+ end
39
+ end
40
+
41
+ def path
42
+ @path_parts.join('/')
43
+ end
44
+
45
+ def create(params: nil, headers: nil, body: nil)
46
+ APIRequest.new(builder: self).post(params: params, headers: headers, body: body)
47
+ ensure
48
+ reset
49
+ end
50
+
51
+ def update(params: nil, headers: nil, body: nil)
52
+ APIRequest.new(builder: self).patch(params: params, headers: headers, body: body)
53
+ ensure
54
+ reset
55
+ end
56
+
57
+ def retrieve(params: nil, headers: nil)
58
+ APIRequest.new(builder: self).get(params: params, headers: headers)
59
+ ensure
60
+ reset
61
+ end
62
+
63
+ def delete(params: nil, headers: nil)
64
+ APIRequest.new(builder: self).delete(params: params, headers: headers)
65
+ ensure
66
+ reset
67
+ end
68
+
69
+ protected
70
+
71
+ def reset
72
+ @path_parts = []
73
+ end
74
+
75
+ class << self
76
+ attr_accessor :api_key, :timeout, :open_timeout, :api_endpoint, :proxy, :faraday_adapter, :symbolize_keys, :debug, :logger
77
+
78
+ def method_missing(sym, *args, &block)
79
+ new(api_key: self.api_key, api_endpoint: self.api_endpoint, timeout: self.timeout, open_timeout: self.open_timeout, faraday_adapter: self.faraday_adapter, symbolize_keys: self.symbolize_keys, debug: self.debug, proxy: self.proxy, logger: self.logger).send(sym, *args, &block)
80
+ end
81
+
82
+ def respond_to_missing?(method_name, include_private = false)
83
+ true
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,10 @@
1
+ module PDRC
2
+ class Response
3
+ attr_accessor :body, :headers
4
+
5
+ def initialize(body: {}, headers: {})
6
+ @body = body
7
+ @headers = headers
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module PDRC
2
+ VERSION = "1.0.0"
3
+ end
data/pdrc.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'pdrc/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "pdrc"
7
+ s.version = PDRC::VERSION
8
+ s.authors = ["Lucas Willett", "Amro Mousa"]
9
+ s.email = ["me@ltw.io", "amromousa@gmail.com"]
10
+ s.homepage = "http://github.com/ltw/pdrc"
11
+
12
+ s.summary = %q{A wrapper for the Pagerduty REST API v2}
13
+ s.description = %q{A wrapper for the Pagerduty REST API v2}
14
+ s.license = "MIT"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ s.required_ruby_version = '>= 2.0.0'
21
+
22
+ s.add_dependency('faraday', '>= 0.9.1')
23
+ s.add_dependency('multi_json', '>= 1.11.0')
24
+
25
+ s.add_development_dependency 'rake'
26
+ s.add_development_dependency "rspec", "3.7.0"
27
+ s.add_development_dependency 'webmock', '~> 1.21.0'
28
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+ require 'webmock/rspec'
3
+
4
+ describe PDRC::APIRequest do
5
+ it 'raises a PDRC::PDRCError if an API key is not specified' do
6
+ @pdrc = PDRC::Request.new
7
+ expect { @pdrc.teams.retrieve }.to raise_error(PDRC::PDRCError)
8
+ end
9
+
10
+ context 'with an API key' do
11
+ let(:api_key) { "XFZ8MisS7d9IytnVniqS" }
12
+
13
+ before do
14
+ @pdrc = PDRC::Request.new(api_key: api_key)
15
+ @api_root = "https://api.pagerduty.com"
16
+ end
17
+
18
+ it "surfaces client request exceptions as a PDRC::PagerdutyError" do
19
+ exception = Faraday::Error::ClientError.new("the server responded with status 503")
20
+ stub_request(:get, "#{@api_root}/teams").to_raise(exception)
21
+ expect { @pdrc.teams.retrieve }.to raise_error(PDRC::PagerdutyError)
22
+ end
23
+
24
+ it "surfaces an unparseable response body as a PDRC::PagerdutyError" do
25
+ response_values = {:status => 503, :headers => {}, :body => '[foo]'}
26
+ exception = Faraday::Error::ClientError.new("the server responded with status 503", response_values)
27
+
28
+ stub_request(:get, "#{@api_root}/teams").to_raise(exception)
29
+ expect { @pdrc.teams.retrieve }.to raise_error(PDRC::PagerdutyError)
30
+ end
31
+
32
+ context 'parse_response' do
33
+ it 'raises a PagerdutyError when the response is successful but contains an unparseable response body' do
34
+ end
35
+ end
36
+
37
+ context "handle_error" do
38
+ it "includes status and raw body even when json can't be parsed" do
39
+ response_values = {:status => 503, :headers => {}, :body => 'A non JSON response'}
40
+ exception = Faraday::Error::ClientError.new("the server responded with status 503", response_values)
41
+ api_request = PDRC::APIRequest.new(builder: PDRC::Request)
42
+ begin
43
+ api_request.send(:handle_error, exception)
44
+ rescue => boom
45
+ expect(boom.status_code).to eq 503
46
+ expect(boom.raw_body).to eq "A non JSON response"
47
+ end
48
+ end
49
+
50
+ context "when symbolize_keys is true" do
51
+ it "sets title and detail on the error params" do
52
+ response_values = {:status => 422, :headers => {}, :body => '{"title": "foo", "detail": "bar"}'}
53
+ exception = Faraday::Error::ClientError.new("the server responded with status 422", response_values)
54
+ api_request = PDRC::APIRequest.new(builder: PDRC::Request.new(symbolize_keys: true))
55
+ begin
56
+ api_request.send(:handle_error, exception)
57
+ rescue => boom
58
+ expect(boom.title).to eq "foo"
59
+ expect(boom.detail).to eq "bar"
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe PDRC::PagerdutyError do
4
+ let(:message) { 'Foo' }
5
+ let(:params) do
6
+ {
7
+ title: 'error_title',
8
+ detail: 'error_detail',
9
+ body: 'error_body',
10
+ raw_body: 'error_raw_body',
11
+ status_code: 'error_status_code'
12
+ }
13
+ end
14
+
15
+ before do
16
+ @pdrc = PDRC::PagerdutyError.new(message, params)
17
+ end
18
+
19
+ it "adds the error params to the error message" do
20
+ expected_message = "Foo " \
21
+ "@title=\"error_title\", " \
22
+ "@detail=\"error_detail\", " \
23
+ "@body=\"error_body\", " \
24
+ "@raw_body=\"error_raw_body\", " \
25
+ "@status_code=\"error_status_code\""
26
+
27
+ expect(@pdrc.message).to eq(expected_message)
28
+ end
29
+
30
+ it 'sets the title attribute' do
31
+ expect(@pdrc.title).to eq(params[:title])
32
+ end
33
+
34
+ it 'sets the detail attribute' do
35
+ expect(@pdrc.detail).to eq(params[:detail])
36
+ end
37
+
38
+ it 'sets the body attribute' do
39
+ expect(@pdrc.body).to eq(params[:body])
40
+ end
41
+
42
+ it 'sets the raw_body attribute' do
43
+ expect(@pdrc.raw_body).to eq(params[:raw_body])
44
+ end
45
+
46
+ it 'sets the status_code attribute' do
47
+ expect(@pdrc.status_code).to eq(params[:status_code])
48
+ end
49
+ end
@@ -0,0 +1,217 @@
1
+ require 'spec_helper'
2
+ require 'cgi'
3
+
4
+ describe PDRC do
5
+ describe "attributes" do
6
+ before do
7
+ PDRC::APIRequest.send(:public, *PDRC::APIRequest.protected_instance_methods)
8
+
9
+ @api_key = "y_NbAkKc66ryYTWUXYEu"
10
+ @proxy = 'the_proxy'
11
+ end
12
+
13
+ it "have no API by default" do
14
+ @pdrc = PDRC::Request.new
15
+ expect(@pdrc.api_key).to be_nil
16
+ end
17
+ it "sets an API key in the constructor" do
18
+ @pdrc = PDRC::Request.new(api_key: @api_key)
19
+ expect(@pdrc.api_key).to eq(@api_key)
20
+ end
21
+
22
+ it "sets an API key from the 'PAGERDUTY_API_KEY' ENV variable" do
23
+ ENV['PAGERDUTY_API_KEY'] = @api_key
24
+ @pdrc = PDRC::Request.new
25
+ expect(@pdrc.api_key).to eq(@api_key)
26
+ ENV.delete('PAGERDUTY_API_KEY')
27
+ end
28
+
29
+ it "sets an API key via setter" do
30
+ @pdrc = PDRC::Request.new
31
+ @pdrc.api_key = @api_key
32
+ expect(@pdrc.api_key).to eq(@api_key)
33
+ end
34
+
35
+ it "sets timeout and get" do
36
+ @pdrc = PDRC::Request.new
37
+ timeout = 30
38
+ @pdrc.timeout = timeout
39
+ expect(timeout).to eq(@pdrc.timeout)
40
+ end
41
+
42
+ it "sets the open_timeout and get" do
43
+ @pdrc = PDRC::Request.new
44
+ open_timeout = 30
45
+ @pdrc.open_timeout = open_timeout
46
+ expect(open_timeout).to eq(@pdrc.open_timeout)
47
+ end
48
+
49
+ it "timeout properly passed to APIRequest" do
50
+ @pdrc = PDRC::Request.new
51
+ timeout = 30
52
+ @pdrc.timeout = timeout
53
+ @request = PDRC::APIRequest.new(builder: @pdrc)
54
+ expect(timeout).to eq(@request.timeout)
55
+ end
56
+
57
+ it "timeout properly based on open_timeout passed to APIRequest" do
58
+ @pdrc = PDRC::Request.new
59
+ open_timeout = 30
60
+ @pdrc.open_timeout = open_timeout
61
+ @request = PDRC::APIRequest.new(builder: @pdrc)
62
+ expect(open_timeout).to eq(@request.open_timeout)
63
+ end
64
+
65
+ it "detect api endpoint from initializer parameters" do
66
+ api_endpoint = 'https://api.pagerduty.com'
67
+ @pdrc = PDRC::Request.new(api_key: @api_key, api_endpoint: api_endpoint)
68
+ expect(api_endpoint).to eq(@pdrc.api_endpoint)
69
+ end
70
+
71
+ it "has no Proxy url by default" do
72
+ @pdrc = PDRC::Request.new
73
+ expect(@pdrc.proxy).to be_nil
74
+ end
75
+
76
+ it "sets an proxy url key from the 'PAGERDUTY_PROXY_URL' ENV variable" do
77
+ ENV['PAGERDUTY_PROXY'] = @proxy
78
+ @pdrc = PDRC::Request.new
79
+ expect(@pdrc.proxy).to eq(@proxy)
80
+ ENV.delete('PAGERDUTY_PROXY')
81
+ end
82
+
83
+ it "sets an API key via setter" do
84
+ @pdrc = PDRC::Request.new
85
+ @pdrc.proxy = @proxy
86
+ expect(@pdrc.proxy).to eq(@proxy)
87
+ end
88
+
89
+ it "sets an adapter in the constructor" do
90
+ adapter = :em_synchrony
91
+ @pdrc = PDRC::Request.new(faraday_adapter: adapter)
92
+ expect(@pdrc.faraday_adapter).to eq(adapter)
93
+ end
94
+
95
+ it "symbolize_keys false by default" do
96
+ @pdrc = PDRC::Request.new
97
+ expect(@pdrc.symbolize_keys).to be false
98
+ end
99
+
100
+ it "sets symbolize_keys in the constructor" do
101
+ @pdrc = PDRC::Request.new(symbolize_keys: true)
102
+ expect(@pdrc.symbolize_keys).to be true
103
+ end
104
+
105
+ it "sets symbolize_keys in the constructor" do
106
+ @pdrc = PDRC::Request.new(symbolize_keys: true)
107
+ expect(@pdrc.symbolize_keys).to be true
108
+ end
109
+ it "debug false by default" do
110
+ @pdrc = PDRC::Request.new
111
+ expect(@pdrc.debug).to be false
112
+ end
113
+
114
+ it "sets debug in the constructor" do
115
+ @pdrc = PDRC::Request.new(debug: true)
116
+ expect(@pdrc.debug).to be true
117
+ end
118
+
119
+ it "sets logger in constructor" do
120
+ logger = double(:logger)
121
+ @pdrc = PDRC::Request.new(logger: logger)
122
+ expect(@pdrc.logger).to eq(logger)
123
+ end
124
+
125
+ it "is a Logger instance by default" do
126
+ @pdrc = PDRC::Request.new
127
+ expect(@pdrc.logger).to be_a Logger
128
+ end
129
+
130
+ end
131
+
132
+ describe "class variables" do
133
+ let(:logger) { double(:logger) }
134
+
135
+ before do
136
+ PDRC::Request.api_key = "XFZ8MisS7d9IytnVniqS"
137
+ PDRC::Request.timeout = 15
138
+ PDRC::Request.api_endpoint = 'https://api.pagerduty.com'
139
+ PDRC::Request.logger = logger
140
+ PDRC::Request.proxy = "http://1234.com"
141
+ PDRC::Request.symbolize_keys = true
142
+ PDRC::Request.faraday_adapter = :net_http
143
+ PDRC::Request.debug = true
144
+ end
145
+
146
+ after do
147
+ PDRC::Request.api_key = nil
148
+ PDRC::Request.timeout = nil
149
+ PDRC::Request.api_endpoint = nil
150
+ PDRC::Request.logger = nil
151
+ PDRC::Request.proxy = nil
152
+ PDRC::Request.symbolize_keys = nil
153
+ PDRC::Request.faraday_adapter = nil
154
+ PDRC::Request.debug = nil
155
+ end
156
+
157
+ it "set api key on new instances" do
158
+ expect(PDRC::Request.new.api_key).to eq(PDRC::Request.api_key)
159
+ end
160
+
161
+ it "set timeout on new instances" do
162
+ expect(PDRC::Request.new.timeout).to eq(PDRC::Request.timeout)
163
+ end
164
+
165
+ it "set api_endpoint on new instances" do
166
+ expect(PDRC::Request.api_endpoint).not_to be_nil
167
+ expect(PDRC::Request.new.api_endpoint).to eq(PDRC::Request.api_endpoint)
168
+ end
169
+
170
+ it "set proxy on new instances" do
171
+ expect(PDRC::Request.new.proxy).to eq(PDRC::Request.proxy)
172
+ end
173
+
174
+ it "set symbolize_keys on new instances" do
175
+ expect(PDRC::Request.new.symbolize_keys).to eq(PDRC::Request.symbolize_keys)
176
+ end
177
+
178
+ it "set debug on new instances" do
179
+ expect(PDRC::Request.new.debug).to eq(PDRC::Request.debug)
180
+ end
181
+
182
+ it "set faraday_adapter on new instances" do
183
+ expect(PDRC::Request.new.faraday_adapter).to eq(PDRC::Request.faraday_adapter)
184
+ end
185
+
186
+ it "set logger on new instances" do
187
+ expect(PDRC::Request.new.logger).to eq(logger)
188
+ end
189
+ end
190
+
191
+ describe "missing methods" do
192
+ it "respond to .method call on class" do
193
+ expect(PDRC::Request.method(:teams)).to be_a(Method)
194
+ end
195
+ it "respond to .method call on instance" do
196
+ expect(PDRC::Request.new.method(:teams)).to be_a(Method)
197
+ end
198
+ end
199
+
200
+ describe 'path building using method missing invocations' do
201
+ it 'constructs a path' do
202
+ expect(PDRC::Request.teams.path).to eq "teams"
203
+ end
204
+
205
+ it 'expands the paths over multiple invocations' do
206
+ expect(PDRC::Request.teams.users.path).to eq "teams/users"
207
+ end
208
+
209
+ it 'includes ids passed in as arguments' do
210
+ expect(PDRC::Request.teams("1234MYTEAM").path).to eq "teams/1234MYTEAM"
211
+ end
212
+
213
+ it 'expands multiple paths with arguments' do
214
+ expect(PDRC::Request.teams("1234-team").users("4321").path).to eq "teams/1234-team/users/4321"
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.setup(:default, :development)
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ require 'pdrc'
9
+
10
+ RSpec.configure do |config|
11
+ config.color = true
12
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pdrc
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Lucas Willett
8
+ - Amro Mousa
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2018-07-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: faraday
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 0.9.1
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 0.9.1
28
+ - !ruby/object:Gem::Dependency
29
+ name: multi_json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 1.11.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 1.11.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '='
61
+ - !ruby/object:Gem::Version
62
+ version: 3.7.0
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '='
68
+ - !ruby/object:Gem::Version
69
+ version: 3.7.0
70
+ - !ruby/object:Gem::Dependency
71
+ name: webmock
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: 1.21.0
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: 1.21.0
84
+ description: A wrapper for the Pagerduty REST API v2
85
+ email:
86
+ - me@ltw.io
87
+ - amromousa@gmail.com
88
+ executables: []
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".document"
93
+ - ".gitignore"
94
+ - ".ruby-gemset"
95
+ - ".ruby-version"
96
+ - ".travis.yml"
97
+ - CHANGELOG.md
98
+ - Gemfile
99
+ - LICENSE.txt
100
+ - README.markdown
101
+ - Rakefile
102
+ - lib/pdrc.rb
103
+ - lib/pdrc/api_request.rb
104
+ - lib/pdrc/pagerduty_error.rb
105
+ - lib/pdrc/pdrc_error.rb
106
+ - lib/pdrc/request.rb
107
+ - lib/pdrc/response.rb
108
+ - lib/pdrc/version.rb
109
+ - pdrc.gemspec
110
+ - spec/pdrc/api_request_spec.rb
111
+ - spec/pdrc/pagerduty_error_spec.rb
112
+ - spec/pdrc/pdrc_spec.rb
113
+ - spec/spec_helper.rb
114
+ homepage: http://github.com/ltw/pdrc
115
+ licenses:
116
+ - MIT
117
+ metadata: {}
118
+ post_install_message:
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: 2.0.0
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ requirements: []
133
+ rubyforge_project:
134
+ rubygems_version: 2.7.7
135
+ signing_key:
136
+ specification_version: 4
137
+ summary: A wrapper for the Pagerduty REST API v2
138
+ test_files: []