nine_one_one 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bc1d95a66273659ccfaac813c2324de176a55e5b
4
+ data.tar.gz: 9d32c8fcf3095ff38f665af3b9ed540b8d2a542a
5
+ SHA512:
6
+ metadata.gz: 8e95ffe1c79216decaace3931588d690365fe1ca98a47eae7f5a5496f52c65ec97382a457acde2dc9e20dfce6a5e8efe793e51ba2b02c06bf34e4a0697859f01
7
+ data.tar.gz: 08b510ec8a4af089217c21092c502396c95d6923ef2051c0b671521e23518bdf05658677860f7b26bbbc9116b983519d4b3c1faef06e40b292c238092961afed
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.idea
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,29 @@
1
+ AllCops:
2
+ Include:
3
+ - '**/Rakefile'
4
+ Exclude:
5
+ - bin/**/*
6
+ - db/**/*
7
+ - vendor/**/*
8
+ TargetRubyVersion: 2.1
9
+
10
+ Style/MultilineOperationIndentation:
11
+ EnforcedStyle: indented
12
+
13
+ Style/Documentation:
14
+ Enabled: false
15
+
16
+ Style/FormatString:
17
+ Enabled: false
18
+
19
+ Style/WhileUntilModifier:
20
+ MaxLineLength: 120
21
+
22
+ Metrics/LineLength:
23
+ Max: 120
24
+ Enabled: true
25
+
26
+ Metrics/BlockLength:
27
+ Exclude:
28
+ - 'spec/**/*'
29
+
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ cache: bundler
3
+ before_install: gem update --remote bundler
4
+ rvm:
5
+ - 2.1.5
6
+ - 2.2.5
7
+ - 2.3.1
8
+ script: "bundle exec rake spec"
9
+ addons:
10
+ code_climate:
11
+ repo_token: c422f2d5b2f42f45b2385d368407e350e1862156e14e4a18cab4d32907be570c
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,21 @@
1
+ guard :rspec, cmd: "bundle exec rspec" do
2
+ require "guard/rspec/dsl"
3
+ dsl = Guard::RSpec::Dsl.new(self)
4
+
5
+ # Feel free to open issues for suggestions and improvements
6
+
7
+ # RSpec files
8
+ rspec = dsl.rspec
9
+ watch(rspec.spec_helper) { rspec.spec_dir }
10
+ watch(rspec.spec_support) { rspec.spec_dir }
11
+ watch(rspec.spec_files)
12
+
13
+ # Ruby files
14
+ ruby = dsl.ruby
15
+ dsl.watch_spec_files_for(ruby.lib_files)
16
+ end
17
+
18
+ guard :rubocop do
19
+ watch(%r{.+\.rb$})
20
+ watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
21
+ end
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ [![Build](https://travis-ci.org/u2i/nine_one_one.svg?branch=master)](https://travis-ci.org/u2i/nine_one_one)
2
+ [![Code
3
+ Climate](https://codeclimate.com/repos/58207e5ee72dfa227600001d/badges/ecd3be37c49334786095/gpa.svg)](https://codeclimate.com/repos/58207e5ee72dfa227600001d/feed)
4
+ [![Test
5
+ Coverage](https://codeclimate.com/repos/58207e5ee72dfa227600001d/badges/ecd3be37c49334786095/coverage.svg)](https://codeclimate.com/repos/58207e5ee72dfa227600001d/coverage)
6
+ [![Issue
7
+ Count](https://codeclimate.com/repos/58207e5ee72dfa227600001d/badges/ecd3be37c49334786095/issue_count.svg)](https://codeclimate.com/repos/58207e5ee72dfa227600001d/feed)
8
+
9
+ # NineOneOne
10
+
11
+ Common notification logic for PagerDuty/Slack notifications.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'nine_one_one'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install nine_one_one
28
+
29
+ ## Configuration
30
+
31
+ By default NineOneOne loggs notifications and emegencies to STDOUT. You can override default settings with:
32
+
33
+ ```ruby
34
+ NineOneOne.configure do |config|
35
+ # Use Pager Duty API for emergencies (defaults to false)
36
+ config.send_pagers = true
37
+ config.pager_duty_integration_key = 'pager-api-key'
38
+
39
+ # Post notifications using Slack Webhook URL (defaults to false)
40
+ config.slack_enabled = true
41
+ config.slack_webhook_url = 'https://hooks.slack.com/services/XXX/YYY/ZZZ'
42
+
43
+ # Use custom logger - it must implement .info(string) and .error(string) methods
44
+ # Defaults to Logger.new(STDOUT)
45
+ config.logger = Logger.new('incidents.log')
46
+ end
47
+ ```
48
+
49
+ ## Usage
50
+
51
+ ```ruby
52
+ # Send message to Slack channel or log it using logger depending on the `slack_enabled` config parameter
53
+ NineOneOne.notify('Something happened!')
54
+
55
+ # Send pager or log emergency using logger depending on the `send_pagers` config parameter
56
+ NineOneOne.emergency('INCIDENT_KEY', 'Emergency message!', { optional_hash: 'with details' })
57
+ ```
58
+
59
+ ## Development
60
+
61
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
62
+
63
+ ## Contributing
64
+
65
+ Bug reports and pull requests are welcome on GitHub at https://github.com/u2i/nine_one_one.
66
+
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ RuboCop::RakeTask.new do |task|
8
+ task.options = %w(--display-cop-names --format simple)
9
+ end
10
+
11
+ task default: [:spec, :rubocop]
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "nine_one_one"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,55 @@
1
+ require 'logger'
2
+
3
+ module NineOneOne
4
+ class Configuration
5
+ attr_accessor :send_pagers, :pager_duty_integration_key, :slack_enabled, :slack_webhook_url, :logger
6
+
7
+ def initialize
8
+ self.send_pagers = false
9
+ self.slack_enabled = false
10
+ self.logger = Logger.new(STDOUT)
11
+ end
12
+
13
+ def validate
14
+ validate_send_pagers
15
+ validate_logger
16
+ validate_pager_duty_key
17
+ validate_slack_enabled
18
+ end
19
+
20
+ private
21
+
22
+ def validate_send_pagers
23
+ unless [true, false].include?(send_pagers)
24
+ raise ConfigurationError, "Illegal 'send_pagers' value: #{send_pagers}"
25
+ end
26
+
27
+ raise ConfigurationError, "'send_pagers' is false but no logger given" if !send_pagers && logger.nil?
28
+ end
29
+
30
+ # rubocop:disable Style/GuardClause
31
+ def validate_logger
32
+ raise ConfigurationError, "Logger: #{logger.class} doesn't respond to #error" unless logger.respond_to?(:error)
33
+ raise ConfigurationError, "Logger: #{logger.class} doesn't respond to #info" unless logger.respond_to?(:info)
34
+ end
35
+
36
+ def validate_pager_duty_key
37
+ return true unless send_pagers
38
+
39
+ if pager_duty_integration_key.nil? || pager_duty_integration_key.empty?
40
+ raise ConfigurationError, "Missing 'pager_duty_integration_key' parameter"
41
+ end
42
+ end
43
+
44
+ def validate_slack_enabled
45
+ unless [true, false].include?(slack_enabled)
46
+ raise ConfigurationError, "Illegal 'slack_enabled' value: #{slack_enabled}"
47
+ end
48
+
49
+ if slack_enabled && (slack_webhook_url.nil? || slack_webhook_url.empty?)
50
+ raise ConfigurationError, 'Incorrect Slack webhook URL'
51
+ end
52
+ end
53
+ # rubocop:enable Style/GuardClause
54
+ end
55
+ end
@@ -0,0 +1,12 @@
1
+ module NineOneOne
2
+ class Error < RuntimeError; end
3
+
4
+ class ConfigurationError < Error; end
5
+ class IncidentReportingError < Error; end
6
+ class NotificationError < Error; end
7
+
8
+ class HttpError < Error; end
9
+ class SSLError < HttpError; end
10
+ class TimeoutError < HttpError; end
11
+ class ConnectionFailedError < HttpError; end
12
+ end
@@ -0,0 +1,68 @@
1
+ begin
2
+ require 'net/https'
3
+ rescue LoadError
4
+ warn 'Warning: no such file to load -- net/https. Make sure openssl is installed if you want ssl support'
5
+ require 'net/http'
6
+ end
7
+ require 'zlib'
8
+
9
+ # a minimal wrapper around Net::HTTP which encapsulates ugly Net::HTTP errors
10
+ # and throws NineOneOne:Errors instead. The implementation is based on
11
+ # Faraday's Net::HTTP adapter
12
+ module NineOneOne
13
+ class Http
14
+ # rubocop:disable Style/MutableConstant
15
+ NET_HTTP_EXCEPTIONS = [
16
+ EOFError,
17
+ Errno::ECONNABORTED,
18
+ Errno::ECONNREFUSED,
19
+ Errno::ECONNRESET,
20
+ Errno::EHOSTUNREACH,
21
+ Errno::EINVAL,
22
+ Errno::ENETUNREACH,
23
+ Errno::EPIPE,
24
+ Net::HTTPBadResponse,
25
+ Net::HTTPHeaderSyntaxError,
26
+ Net::ProtocolError,
27
+ SocketError,
28
+ Zlib::GzipFile::Error
29
+ ]
30
+ # rubocop:enable Style/MutableConstant
31
+
32
+ NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL)
33
+ NET_HTTP_EXCEPTIONS << Net::OpenTimeout if defined?(Net::OpenTimeout)
34
+
35
+ attr_reader :net_http
36
+
37
+ def initialize(base_host, scheme = 'https')
38
+ port, use_ssl = scheme == 'https' ? [443, true] : [80, false]
39
+
40
+ @net_http = Net::HTTP.new(base_host, port)
41
+
42
+ @net_http.use_ssl = use_ssl
43
+ end
44
+
45
+ def post(path, body, headers)
46
+ post!(path, body, headers)
47
+ rescue *NET_HTTP_EXCEPTIONS => err
48
+ err_class = if defined?(OpenSSL) && err.is_a?(OpenSSL::SSL::SSLError)
49
+ SSLError
50
+ else
51
+ ConnectionFailedError
52
+ end
53
+
54
+ raise err_class, err
55
+ rescue Timeout::Error, Errno::ETIMEDOUT => err
56
+ raise TimeoutError, err
57
+ end
58
+
59
+ private
60
+
61
+ def post!(path, body, headers)
62
+ request = Net::HTTP::Post.new(path, headers)
63
+ request.body = body
64
+
65
+ net_http.request(request)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,19 @@
1
+ module NineOneOne
2
+ class LogService
3
+ def initialize(logger)
4
+ @logger = logger
5
+ end
6
+
7
+ def trigger_event(incident_key, description, details_hash = nil)
8
+ logger.error "TRIGGERED INCIDENT #{incident_key}: #{description} #{details_hash}"
9
+ end
10
+
11
+ def notify(message)
12
+ logger.info(message)
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :logger
18
+ end
19
+ end
@@ -0,0 +1,61 @@
1
+ module NineOneOne
2
+ class PagerDutyService
3
+ BASE_HOST = 'events.pagerduty.com'.freeze
4
+ EVENT_ENDPOINT = '/generic/2010-04-15/create_event.json'.freeze
5
+
6
+ THROTTLE_HTTP_STATUS = 403
7
+ THROTTLE_RETRIES = 2
8
+
9
+ def initialize(api_integration_key)
10
+ @api_integration_key = api_integration_key
11
+ @http = Http.new(BASE_HOST)
12
+ end
13
+
14
+ def trigger_event(incident_key, description, details_hash = nil)
15
+ response = nil
16
+
17
+ retry_on(THROTTLE_HTTP_STATUS, THROTTLE_RETRIES) do
18
+ response = make_request(description, details_hash, incident_key)
19
+ response.code.to_i
20
+ end
21
+
22
+ # rubocop:disable Style/GuardClause
23
+ unless response.is_a?(Net::HTTPSuccess)
24
+ raise IncidentReportingError, "Failed to create PagerDuty event: #{response.body}"
25
+ end
26
+ # rubocop:enable Style/GuardClause
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :api_integration_key, :http
32
+
33
+ def retry_on(value, retries_number)
34
+ retry_number = 0
35
+
36
+ while yield == value && retry_number <= retries_number
37
+ retry_number += 1
38
+ sleep 2**retry_number
39
+ end
40
+ end
41
+
42
+ def make_request(description, details_hash, incident_key)
43
+ headers = { 'Content-Type' => 'application/json' }
44
+ body = request_body(incident_key, description, details_hash)
45
+
46
+ http.post(EVENT_ENDPOINT, body, headers)
47
+ end
48
+
49
+ def request_body(incident_key, description, details_hash)
50
+ body = {
51
+ service_key: api_integration_key,
52
+ event_type: 'trigger',
53
+ incident_key: incident_key,
54
+ description: description
55
+ }
56
+ body[:details] = details_hash if details_hash
57
+
58
+ body.to_json
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,27 @@
1
+ module NineOneOne
2
+ class SlackService
3
+ def initialize(webhook_url)
4
+ uri = URI(webhook_url)
5
+
6
+ @http = Http.new(uri.host, uri.scheme)
7
+ @path = uri.path
8
+ end
9
+
10
+ def notify(message)
11
+ body = request_body(message)
12
+ headers = { 'Content-Type' => 'application/json' }
13
+
14
+ response = http.post(path, body, headers)
15
+
16
+ response.is_a?(Net::HTTPSuccess)
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :http, :path
22
+
23
+ def request_body(message)
24
+ { text: message }.to_json
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module NineOneOne
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,47 @@
1
+ require_relative './nine_one_one/errors'
2
+ require_relative './nine_one_one/http'
3
+ require_relative './nine_one_one/version'
4
+ require_relative './nine_one_one/configuration'
5
+ require_relative './nine_one_one/log_service'
6
+ require_relative './nine_one_one/slack_service'
7
+ require_relative './nine_one_one/pager_duty_service'
8
+
9
+ module NineOneOne
10
+ def self.emergency_service
11
+ if config.send_pagers
12
+ PagerDutyService.new(config.pager_duty_integration_key)
13
+ else
14
+ LogService.new(config.logger)
15
+ end
16
+ end
17
+
18
+ def self.notification_service
19
+ if config.slack_enabled
20
+ SlackService.new(config.slack_webhook_url)
21
+ else
22
+ LogService.new(config.logger)
23
+ end
24
+ end
25
+
26
+ def self.configure
27
+ config = Configuration.new
28
+
29
+ yield config
30
+
31
+ config.validate
32
+
33
+ @config = config
34
+ end
35
+
36
+ def self.config
37
+ @config ||= Configuration.new
38
+ end
39
+
40
+ def self.emergency(incident_key, description, details_hash = nil)
41
+ emergency_service.trigger_event(incident_key, description, details_hash)
42
+ end
43
+
44
+ def self.notify(message)
45
+ notification_service.notify(message)
46
+ end
47
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'nine_one_one/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'nine_one_one'
8
+ spec.version = NineOneOne::VERSION
9
+ spec.licenses = ['MIT']
10
+ spec.authors = ['Kacper Madej', 'Marek Mateja']
11
+ spec.email = %w(kacper.madej@u2i.com marek.mateja@u2i.com)
12
+
13
+ spec.summary = %q{Alerts and notifications via PagerDuty and Slack for Ruby apps}
14
+ spec.homepage = 'https://github.com/u2i/nine_one_one'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+ spec.required_ruby_version = '>= 2.1'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.13'
25
+ spec.add_development_dependency 'guard', '~> 2.14'
26
+ spec.add_development_dependency 'guard-rspec', '~> 4.7'
27
+ spec.add_development_dependency 'guard-rubocop', '~> 1.2'
28
+ spec.add_development_dependency 'rake', '~> 10.0'
29
+ spec.add_development_dependency 'rspec', '~> 3.0'
30
+ spec.add_development_dependency 'rubocop', '~> 0.47'
31
+ spec.add_development_dependency 'vcr', '~> 3.0'
32
+ spec.add_development_dependency 'webmock', '~> 2.3'
33
+ spec.add_development_dependency 'codeclimate-test-reporter', '~> 1.0'
34
+ spec.add_development_dependency 'simplecov', '~> 0.13'
35
+ end
metadata ADDED
@@ -0,0 +1,219 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nine_one_one
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kacper Madej
8
+ - Marek Mateja
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2017-02-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.13'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.13'
28
+ - !ruby/object:Gem::Dependency
29
+ name: guard
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '2.14'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '2.14'
42
+ - !ruby/object:Gem::Dependency
43
+ name: guard-rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '4.7'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '4.7'
56
+ - !ruby/object:Gem::Dependency
57
+ name: guard-rubocop
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '1.2'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.2'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rake
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '10.0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '10.0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '3.0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '3.0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rubocop
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '0.47'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '0.47'
112
+ - !ruby/object:Gem::Dependency
113
+ name: vcr
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '3.0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '3.0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: webmock
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - "~>"
131
+ - !ruby/object:Gem::Version
132
+ version: '2.3'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: '2.3'
140
+ - !ruby/object:Gem::Dependency
141
+ name: codeclimate-test-reporter
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - "~>"
145
+ - !ruby/object:Gem::Version
146
+ version: '1.0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - "~>"
152
+ - !ruby/object:Gem::Version
153
+ version: '1.0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: simplecov
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: '0.13'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - "~>"
166
+ - !ruby/object:Gem::Version
167
+ version: '0.13'
168
+ description:
169
+ email:
170
+ - kacper.madej@u2i.com
171
+ - marek.mateja@u2i.com
172
+ executables: []
173
+ extensions: []
174
+ extra_rdoc_files: []
175
+ files:
176
+ - ".gitignore"
177
+ - ".rspec"
178
+ - ".rubocop.yml"
179
+ - ".travis.yml"
180
+ - Gemfile
181
+ - Guardfile
182
+ - README.md
183
+ - Rakefile
184
+ - bin/console
185
+ - bin/setup
186
+ - lib/nine_one_one.rb
187
+ - lib/nine_one_one/configuration.rb
188
+ - lib/nine_one_one/errors.rb
189
+ - lib/nine_one_one/http.rb
190
+ - lib/nine_one_one/log_service.rb
191
+ - lib/nine_one_one/pager_duty_service.rb
192
+ - lib/nine_one_one/slack_service.rb
193
+ - lib/nine_one_one/version.rb
194
+ - nine_one_one.gemspec
195
+ homepage: https://github.com/u2i/nine_one_one
196
+ licenses:
197
+ - MIT
198
+ metadata: {}
199
+ post_install_message:
200
+ rdoc_options: []
201
+ require_paths:
202
+ - lib
203
+ required_ruby_version: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '2.1'
208
+ required_rubygems_version: !ruby/object:Gem::Requirement
209
+ requirements:
210
+ - - ">="
211
+ - !ruby/object:Gem::Version
212
+ version: '0'
213
+ requirements: []
214
+ rubyforge_project:
215
+ rubygems_version: 2.5.1
216
+ signing_key:
217
+ specification_version: 4
218
+ summary: Alerts and notifications via PagerDuty and Slack for Ruby apps
219
+ test_files: []