comsat 0.0.8 → 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 +7 -0
- data/Rakefile +3 -0
- data/comsat.gemspec +4 -2
- data/lib/comsat.rb +70 -0
- data/lib/comsat/client.rb +42 -3
- data/lib/comsat/helpers/auth_helper.rb +8 -2
- data/lib/comsat/service.rb +23 -5
- data/lib/comsat/services/campfire.rb +18 -2
- data/lib/comsat/services/failure.rb +10 -0
- data/lib/comsat/services/github.rb +73 -0
- data/lib/comsat/services/pagerduty.rb +1 -1
- data/lib/comsat/services/sendgrid.rb +47 -0
- data/lib/comsat/version.rb +1 -1
- data/lib/vendor/pony.rb +240 -0
- data/spec/client_spec.rb +20 -0
- data/spec/spec_helper.rb +8 -1
- metadata +69 -27
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f4c6ca9bccc0e70fd2180c5a4460ff3c5fd8fdc2
|
4
|
+
data.tar.gz: 7f45e7c4e5f04a9b3d4f9938d55b2f513c7f5e88
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: deab0d651d199f76efeede9035c32d0d0185c5fc9dbea3cacd608a27765f94dd987956dbb53a9b8234e5f88f2b8fe3b5381483b8c73b61cfbecd5a85aa10da24
|
7
|
+
data.tar.gz: 50e7e0acfe26403d1bcf0022a00c9b8cceabf95168168d4667bf61904b758117f205211e13c112c195afe6616087fb63f2589642fe0461f47965ede96c999862
|
data/Rakefile
CHANGED
data/comsat.gemspec
CHANGED
@@ -3,10 +3,10 @@ require File.expand_path('../lib/comsat/version', __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Curt Micol", "Michael Gorsuch"]
|
6
|
-
gem.email = ["
|
6
|
+
gem.email = ["asenchi@asenchi.com"]
|
7
7
|
gem.description = "Notifications as a Gem"
|
8
8
|
gem.summary = "Notifications as a Gem"
|
9
|
-
gem.homepage = "https://github.com/
|
9
|
+
gem.homepage = "https://github.com/asenchi/comsat"
|
10
10
|
|
11
11
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
12
|
gem.files = `git ls-files`.split("\n")
|
@@ -15,6 +15,8 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Comsat::VERSION
|
17
17
|
|
18
|
+
gem.add_runtime_dependency('octokit')
|
19
|
+
gem.add_runtime_dependency('pony')
|
18
20
|
gem.add_runtime_dependency('rest-client')
|
19
21
|
gem.add_runtime_dependency('scrolls')
|
20
22
|
|
data/lib/comsat.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require "cgi"
|
2
2
|
require "json"
|
3
|
+
require "octokit"
|
4
|
+
require "pony"
|
3
5
|
require "rest_client"
|
4
6
|
|
5
7
|
require "comsat/client"
|
@@ -10,7 +12,10 @@ require "comsat/version"
|
|
10
12
|
require "comsat/helpers/auth_helper"
|
11
13
|
|
12
14
|
require "comsat/services/campfire"
|
15
|
+
require "comsat/services/failure"
|
16
|
+
require "comsat/services/github"
|
13
17
|
require "comsat/services/pagerduty"
|
18
|
+
require "comsat/services/sendgrid"
|
14
19
|
|
15
20
|
module Comsat
|
16
21
|
|
@@ -18,15 +23,80 @@ module Comsat
|
|
18
23
|
data1.merge(data2)
|
19
24
|
end
|
20
25
|
|
26
|
+
# Public: Allows the user to specify a logger for the log messages that Comsat
|
27
|
+
# produces.
|
28
|
+
#
|
29
|
+
# logger = The object you want logs to be sent too
|
30
|
+
#
|
31
|
+
# Examples
|
32
|
+
#
|
33
|
+
# Comsat.instrument_with(STDOUT.method(:puts))
|
34
|
+
# # => #<Method: IO#puts>
|
35
|
+
#
|
36
|
+
# Returns the logger object
|
21
37
|
def self.instrument_with(logger)
|
22
38
|
@logger = logger
|
23
39
|
end
|
24
40
|
|
41
|
+
# Public: Turns on mocking mode
|
42
|
+
#
|
43
|
+
# Examples
|
44
|
+
#
|
45
|
+
# Comsat.mock!
|
46
|
+
# # => true
|
47
|
+
def self.mock!
|
48
|
+
@mock = true
|
49
|
+
end
|
50
|
+
|
51
|
+
# Public: Checks if mocking mode is enabled
|
52
|
+
#
|
53
|
+
# Examples
|
54
|
+
#
|
55
|
+
# Comsat.mocking?
|
56
|
+
# # => false
|
57
|
+
# Comsat.mock!
|
58
|
+
# Comsat.mocking?
|
59
|
+
# # => true
|
60
|
+
#
|
61
|
+
# Returns the state of mocking
|
62
|
+
def self.mocking?
|
63
|
+
!!@mock
|
64
|
+
end
|
65
|
+
|
66
|
+
# Public: Store mocked notifications
|
67
|
+
#
|
68
|
+
# Returns an Array of notifications
|
69
|
+
def self.notifications
|
70
|
+
@notifications ||= []
|
71
|
+
end
|
72
|
+
|
73
|
+
# Public: View the the currently instrumented logger
|
74
|
+
#
|
75
|
+
# Returns the logger object
|
25
76
|
def self.logger
|
26
77
|
@logger || STDOUT.method(:puts)
|
27
78
|
end
|
28
79
|
|
80
|
+
# Internal: Top level log method for use by Comsat
|
81
|
+
#
|
82
|
+
# data = Logging data (typically a hash)
|
83
|
+
# blk = block to execute
|
84
|
+
#
|
85
|
+
# Returns the response from calling the logger with the arguments
|
29
86
|
def self.log(data, &blk)
|
30
87
|
logger.call({:lib => :comsat}.merge(data), &blk)
|
31
88
|
end
|
89
|
+
|
90
|
+
# Public: Reset the mocked data
|
91
|
+
#
|
92
|
+
# Examples
|
93
|
+
#
|
94
|
+
# Comsat.notifications
|
95
|
+
# # => [{..}]
|
96
|
+
# Comsat.reset!
|
97
|
+
# Comsat.notifications
|
98
|
+
# # => []
|
99
|
+
def self.reset!
|
100
|
+
@notifications = []
|
101
|
+
end
|
32
102
|
end
|
data/lib/comsat/client.rb
CHANGED
@@ -10,6 +10,17 @@ module Comsat
|
|
10
10
|
@@routes
|
11
11
|
end
|
12
12
|
|
13
|
+
# Public: Create a route for the specified services
|
14
|
+
#
|
15
|
+
# route - Name of the route we want to create
|
16
|
+
# event_type - Tie this route to a specific event type (notice, alert, resolve)
|
17
|
+
# services - An array of service url's
|
18
|
+
#
|
19
|
+
# Examples
|
20
|
+
#
|
21
|
+
# client.create_route("my_route", [campfire://localhost, pagerduty://localhost])
|
22
|
+
#
|
23
|
+
# Returns the created route object
|
13
24
|
def create_route(route, event_type=nil, services)
|
14
25
|
start = Time.now
|
15
26
|
Comsat.log(:fn => :create_route, :route => "#{route}", :at => :start)
|
@@ -19,11 +30,27 @@ module Comsat
|
|
19
30
|
Comsat.log(:fn => :create_route, :route => "#{route}", :at => :finish, :elapsed => Time.now - start)
|
20
31
|
end
|
21
32
|
|
33
|
+
# Public: Notify a particular route
|
34
|
+
#
|
35
|
+
# route - Name of the route we want to notify
|
36
|
+
# msg - Message payload (Hash)
|
37
|
+
# message - The actual test of the message
|
38
|
+
# message_id - unique identifier for the message
|
39
|
+
# source - The source of the message (helps identify where it came from)
|
40
|
+
# message_type - Event type, notice, alert or resolve (optional)
|
41
|
+
#
|
42
|
+
# Examples
|
43
|
+
#
|
44
|
+
# client.notify("my_route", {:message => "my message", :message_id =>
|
45
|
+
# "unique id", :source => "me", :message_type => "notice"})
|
46
|
+
#
|
47
|
+
# Returns false if there are failed notifications
|
22
48
|
def notify(route, msg={})
|
23
49
|
message = msg.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
24
50
|
|
51
|
+
success = true
|
25
52
|
start = Time.now
|
26
|
-
Comsat.log(:fn => :notify, :route =>
|
53
|
+
Comsat.log(:fn => :notify, :route => route, :at => :start)
|
27
54
|
notify_route = @@routes.detect {|r| r.name == route } if message
|
28
55
|
|
29
56
|
if notify_route.event_type
|
@@ -35,10 +62,22 @@ module Comsat
|
|
35
62
|
end
|
36
63
|
|
37
64
|
notify_route.services[event].each do |svc|
|
38
|
-
Comsat.log(:fn => :notify, :service =>
|
39
|
-
|
65
|
+
Comsat.log(:fn => :notify, :service => svc.class.to_s.downcase, :event => event)
|
66
|
+
begin
|
67
|
+
if Comsat.mocking? && !svc.is_a?(Comsat::Failure) && !svc.nil?
|
68
|
+
Comsat.notifications << { :route => route, :service => svc.class.to_s.downcase, :event => event, :message => message }
|
69
|
+
else
|
70
|
+
svc.send("send_#{event}".to_sym, message)
|
71
|
+
end
|
72
|
+
rescue Exception => e
|
73
|
+
success = false
|
74
|
+
Comsat.log(:fn => :notify, :service => "#{svc.class.to_s.downcase}", :event => event, :error => e.class, :message => e.message)
|
75
|
+
end
|
40
76
|
end
|
77
|
+
|
41
78
|
Comsat.log(:fn => :notify, :route => "#{route}", :at => :finish, :elapsed => Time.now - start)
|
79
|
+
|
80
|
+
success
|
42
81
|
end
|
43
82
|
end
|
44
83
|
end
|
@@ -15,10 +15,16 @@ module Comsat
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.to_hash
|
18
|
+
if @uri.user.include?('%')
|
19
|
+
user = CGI.unescape(@uri.user)
|
20
|
+
else
|
21
|
+
user = @uri.user
|
22
|
+
end
|
23
|
+
|
18
24
|
{
|
19
25
|
:name => @uri.scheme,
|
20
|
-
:api_key =>
|
21
|
-
:username =>
|
26
|
+
:api_key => user,
|
27
|
+
:username => user,
|
22
28
|
:password => @uri.password,
|
23
29
|
:host => @uri.host,
|
24
30
|
:scope => CGI.unescape(@uri.path.gsub(/\A\//, ''))
|
data/lib/comsat/service.rb
CHANGED
@@ -11,13 +11,31 @@ module Comsat
|
|
11
11
|
"#<#{self.class} @host='#{@credentials.host}', @scope='#{@credentials.scope}'>"
|
12
12
|
end
|
13
13
|
|
14
|
-
def http_post
|
14
|
+
def http_post(url, payload, headers={}, &blk)
|
15
|
+
retries = 0
|
16
|
+
begin
|
17
|
+
RestClient.post(url, payload, headers, &blk)
|
18
|
+
rescue RestClient::ServerBrokeConnection => e
|
19
|
+
retries += 1
|
20
|
+
raise if retries >= 3
|
21
|
+
Comsat.log(:fn => :http_post, :at => :exception, :error => e.class, :retry => retries)
|
22
|
+
retry
|
23
|
+
rescue RestClient::RequestTimeout
|
24
|
+
raise
|
25
|
+
end
|
15
26
|
end
|
16
27
|
|
17
|
-
def http_get
|
18
|
-
|
19
|
-
|
20
|
-
|
28
|
+
def http_get(url, headers={}, &blk)
|
29
|
+
begin
|
30
|
+
RestClient.get(url, headers, &blk)
|
31
|
+
rescue RestClient::ServerBrokeConnection => e
|
32
|
+
retries += 1
|
33
|
+
raise if retries >= 3
|
34
|
+
Comsat.log(:fn => :http_get, :at => :exception, :error => e.class, :retry => retries)
|
35
|
+
retry
|
36
|
+
rescue RestClient::RequestTimeout
|
37
|
+
raise
|
38
|
+
end
|
21
39
|
end
|
22
40
|
end
|
23
41
|
end
|
@@ -29,14 +29,30 @@ module Comsat
|
|
29
29
|
if @credentials.scope.to_i > 0
|
30
30
|
@room = {"id" => @credentials.scope.to_i}
|
31
31
|
else
|
32
|
-
|
32
|
+
|
33
|
+
begin
|
34
|
+
rooms = JSON.parse(campfire['/rooms.json'].get)
|
35
|
+
rescue RestClient::ServerBrokeConnection => e
|
36
|
+
retries += 1
|
37
|
+
raise if retries >= 3
|
38
|
+
Comsat.log(:fn => :find_room, :at => :get_room, :error => e.class, :retry => retries)
|
39
|
+
retry
|
40
|
+
end
|
41
|
+
|
33
42
|
@room = rooms["rooms"].select {|r| r["name"] == @credentials.scope }
|
34
43
|
@room.first
|
35
44
|
end
|
36
45
|
end
|
37
46
|
|
38
47
|
def speak(room, message)
|
39
|
-
|
48
|
+
begin
|
49
|
+
campfire["/room/#{room}/speak.json"].post(JSON.dump({:message => message}))
|
50
|
+
rescue RestClient::ServerBrokeConnection => e
|
51
|
+
retries += 1
|
52
|
+
raise if retries >= 3
|
53
|
+
Comsat.log(:fn => :speak, :at => :get_room, :error => e.class, :retry => retries)
|
54
|
+
retry
|
55
|
+
end
|
40
56
|
end
|
41
57
|
end
|
42
58
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# GitHub Comsat URI: github://<api_key>:X@github.com/user/repo
|
2
|
+
module Comsat
|
3
|
+
class Github < Service::Base
|
4
|
+
def send_notice(data)
|
5
|
+
issue = github_client.issues(github_repo, {
|
6
|
+
:state => 'open',
|
7
|
+
}).select { |i|
|
8
|
+
i.title.start_with? issue_title(data)
|
9
|
+
}.first
|
10
|
+
|
11
|
+
if issue.nil?
|
12
|
+
create_issue(data)
|
13
|
+
else
|
14
|
+
update_issue(data)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
alias :send_alert :send_notice
|
18
|
+
|
19
|
+
def send_resolve(data)
|
20
|
+
issue = github_client.issues(github_repo, {
|
21
|
+
:state => 'open',
|
22
|
+
}).select { |i|
|
23
|
+
i.title.start_with? issue_title(data)
|
24
|
+
}.first
|
25
|
+
|
26
|
+
unless issue.nil?
|
27
|
+
close_issue(issue.number, data)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def github_token
|
34
|
+
@credentials.api_key
|
35
|
+
end
|
36
|
+
|
37
|
+
def github_repo
|
38
|
+
@credentials.scope
|
39
|
+
end
|
40
|
+
|
41
|
+
def github_client
|
42
|
+
@client = Octokit::Client.new(:access_token => github_token)
|
43
|
+
end
|
44
|
+
|
45
|
+
def issue_title(data)
|
46
|
+
"[#{data[:source]}] #{data[:message_id]}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def issue_body(data)
|
50
|
+
"\n#{data[:message]}\n"
|
51
|
+
end
|
52
|
+
|
53
|
+
def issue_comment(data)
|
54
|
+
"[#{data[:source]}] #{data[:message_id]}\n#{data[:message]}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_issue(data)
|
58
|
+
title = issue_title(data)
|
59
|
+
body = issue_body(data)
|
60
|
+
github_client.create_issue(github_repo, title, body)
|
61
|
+
end
|
62
|
+
|
63
|
+
def update_issue(issue, data)
|
64
|
+
body = issue_comment(data)
|
65
|
+
github_client.add_comment(github_repo, issue, body)
|
66
|
+
end
|
67
|
+
|
68
|
+
def close_issue(issue, data)
|
69
|
+
github_client.add_comment(github_repo, issue, data[:message])
|
70
|
+
github_client.close_issue(github_repo, issue)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Comsat
|
2
|
+
# A simple Failure class to test mocking
|
3
|
+
class Sendgrid < Service::Base
|
4
|
+
def send_notice(data)
|
5
|
+
contact_sendgrid(data)
|
6
|
+
end
|
7
|
+
alias :send_alert :send_notice
|
8
|
+
alias :send_resolve :send_notice
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def contact_sendgrid(data)
|
13
|
+
id = data[:message_id] || rand(100_000)
|
14
|
+
message = data[:message]
|
15
|
+
source = data[:source]
|
16
|
+
message = "[#{source}] #{message}"
|
17
|
+
|
18
|
+
Pony.mail(
|
19
|
+
:from => "#{source}@comsat.notify",
|
20
|
+
:to => @credentials.scope,
|
21
|
+
:subject => message,
|
22
|
+
:body => "Notification from Comsat\n\nMessage-ID: #{id}",
|
23
|
+
:via => :smtp,
|
24
|
+
:via_options => {
|
25
|
+
:address => 'smtp.sendgrid.net',
|
26
|
+
:port => '587',
|
27
|
+
:user_name => sendgrid_user,
|
28
|
+
:password => sendgrid_api_key,
|
29
|
+
:authentication => :plain,
|
30
|
+
:domain => "comsat.notify"
|
31
|
+
}
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def sendgrid_url
|
36
|
+
"https://#{@credentials.host}/api/mail.send.json"
|
37
|
+
end
|
38
|
+
|
39
|
+
def sendgrid_user
|
40
|
+
@credentials.username
|
41
|
+
end
|
42
|
+
|
43
|
+
def sendgrid_api_key
|
44
|
+
@credentials.password
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/comsat/version.rb
CHANGED
data/lib/vendor/pony.rb
ADDED
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'mail'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
# = The express way to send email in Ruby
|
5
|
+
#
|
6
|
+
# == Overview
|
7
|
+
#
|
8
|
+
# Ruby no longer has to be jealous of PHP's mail() function, which can send an email in a single command.
|
9
|
+
#
|
10
|
+
# Pony.mail(:to => 'you@example.com', :from => 'me@example.com', :subject => 'hi', :body => 'Hello there.')
|
11
|
+
# Pony.mail(:to => 'you@example.com', :html_body => '<h1>Hello there!</h1>', :body => "In case you can't read html, Hello there.")
|
12
|
+
# Pony.mail(:to => 'you@example.com', :cc => 'him@example.com', :from => 'me@example.com', :subject => 'hi', :body => 'Howsit!')
|
13
|
+
#
|
14
|
+
# Any option key may be omitted except for :to. For a complete list of options, see List Of Options section below.
|
15
|
+
#
|
16
|
+
#
|
17
|
+
# == Transport
|
18
|
+
#
|
19
|
+
# Pony uses /usr/sbin/sendmail to send mail if it is available, otherwise it uses SMTP to localhost.
|
20
|
+
#
|
21
|
+
# This can be over-ridden if you specify a via option:
|
22
|
+
#
|
23
|
+
# Pony.mail(:to => 'you@example.com', :via => :smtp) # sends via SMTP
|
24
|
+
#
|
25
|
+
# Pony.mail(:to => 'you@example.com', :via => :sendmail) # sends via sendmail
|
26
|
+
#
|
27
|
+
# You can also specify options for SMTP:
|
28
|
+
#
|
29
|
+
# Pony.mail(:to => 'you@example.com', :via => :smtp, :via_options => {
|
30
|
+
# :address => 'smtp.yourserver.com',
|
31
|
+
# :port => '25',
|
32
|
+
# :user_name => 'user',
|
33
|
+
# :password => 'password',
|
34
|
+
# :authentication => :plain, # :plain, :login, :cram_md5, no auth by default
|
35
|
+
# :domain => "localhost.localdomain" # the HELO domain provided by the client to the server
|
36
|
+
# }
|
37
|
+
#
|
38
|
+
# Gmail example (with TLS/SSL)
|
39
|
+
#
|
40
|
+
# Pony.mail(:to => 'you@example.com', :via => :smtp, :via_options => {
|
41
|
+
# :address => 'smtp.gmail.com',
|
42
|
+
# :port => '587',
|
43
|
+
# :enable_starttls_auto => true,
|
44
|
+
# :user_name => 'user',
|
45
|
+
# :password => 'password',
|
46
|
+
# :authentication => :plain, # :plain, :login, :cram_md5, no auth by default
|
47
|
+
# :domain => "localhost.localdomain" # the HELO domain provided by the client to the server
|
48
|
+
# })
|
49
|
+
#
|
50
|
+
# And options for Sendmail:
|
51
|
+
#
|
52
|
+
# Pony.mail(:to => 'you@example.com', :via => :smtp, :via_options => {
|
53
|
+
# :location => '/path/to/sendmail' # this defaults to 'which sendmail' or '/usr/sbin/sendmail' if 'which' fails
|
54
|
+
# :arguments => '-t' # -t and -i are the defaults
|
55
|
+
# }
|
56
|
+
#
|
57
|
+
# == Attachments
|
58
|
+
#
|
59
|
+
# You can attach a file or two with the :attachments option:
|
60
|
+
#
|
61
|
+
# Pony.mail(..., :attachments => {"foo.zip" => File.read("path/to/foo.zip"), "hello.txt" => "hello!"})
|
62
|
+
#
|
63
|
+
# Note: An attachment's mime-type is set based on the filename (as dictated by the ruby gem mime-types). So 'foo.pdf' has a mime-type of 'application/pdf'
|
64
|
+
#
|
65
|
+
# == Custom Headers
|
66
|
+
#
|
67
|
+
# Pony allows you to specify custom mail headers
|
68
|
+
# Pony.mail(
|
69
|
+
# :to => 'me@example.com',
|
70
|
+
# :headers => { "List-ID" => "...", "X-My-Custom-Header" => "what a cool custom header" }
|
71
|
+
# )
|
72
|
+
#
|
73
|
+
# == List Of Options
|
74
|
+
#
|
75
|
+
# Options passed pretty much directly to Mail
|
76
|
+
# to
|
77
|
+
# cc
|
78
|
+
# bcc
|
79
|
+
# from
|
80
|
+
# body # the plain text body
|
81
|
+
# html_body # for sending html-formatted email
|
82
|
+
# subject
|
83
|
+
# charset # In case you need to send in utf-8 or similar
|
84
|
+
# text_part_charset # for multipart messages, set the charset of the text part
|
85
|
+
# attachments # see Attachments section above
|
86
|
+
# headers # see Custom headers section above
|
87
|
+
# message_id
|
88
|
+
# sender # Sets "envelope from" (and the Sender header)
|
89
|
+
# reply_to
|
90
|
+
#
|
91
|
+
# Other options
|
92
|
+
# via # :smtp or :sendmail, see Transport section above
|
93
|
+
# via_options # specify transport options, see Transport section above
|
94
|
+
#
|
95
|
+
# == Set default options
|
96
|
+
#
|
97
|
+
# Default options can be set so that they don't have to be repeated. The default options you set will be overriden by any options you pass in to Pony.mail()
|
98
|
+
#
|
99
|
+
# Pony.options = { :from => 'noreply@example.com', :via => :smtp, :via_options => { :host => 'smtp.yourserver.com' } }
|
100
|
+
# Pony.mail(:to => 'foo@bar') # Sends mail to foo@bar from noreply@example.com using smtp
|
101
|
+
# Pony.mail(:from => 'pony@example.com', :to => 'foo@bar') # Sends mail to foo@bar from pony@example.com using smtp
|
102
|
+
|
103
|
+
|
104
|
+
module Pony
|
105
|
+
|
106
|
+
@@options = {}
|
107
|
+
|
108
|
+
# Default options can be set so that they don't have to be repeated.
|
109
|
+
#
|
110
|
+
# Pony.options = { :from => 'noreply@example.com', :via => :smtp, :via_options => { :host => 'smtp.yourserver.com' } }
|
111
|
+
# Pony.mail(:to => 'foo@bar') # Sends mail to foo@bar from noreply@example.com using smtp
|
112
|
+
# Pony.mail(:from => 'pony@example.com', :to => 'foo@bar') # Sends mail to foo@bar from pony@example.com using smtp
|
113
|
+
def self.options=(value)
|
114
|
+
@@options = value
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.options()
|
118
|
+
@@options
|
119
|
+
end
|
120
|
+
|
121
|
+
# Send an email
|
122
|
+
# Pony.mail(:to => 'you@example.com', :from => 'me@example.com', :subject => 'hi', :body => 'Hello there.')
|
123
|
+
# Pony.mail(:to => 'you@example.com', :html_body => '<h1>Hello there!</h1>', :body => "In case you can't read html, Hello there.")
|
124
|
+
# Pony.mail(:to => 'you@example.com', :cc => 'him@example.com', :from => 'me@example.com', :subject => 'hi', :body => 'Howsit!')
|
125
|
+
def self.mail(options)
|
126
|
+
options = @@options.merge options
|
127
|
+
raise(ArgumentError, ":to is required") unless options[:to]
|
128
|
+
|
129
|
+
options[:via] = default_delivery_method unless options.has_key?(:via)
|
130
|
+
|
131
|
+
options = cross_reference_depricated_fields(options)
|
132
|
+
|
133
|
+
if options.has_key?(:via) && options[:via] == :sendmail
|
134
|
+
options[:via_options] ||= {}
|
135
|
+
options[:via_options][:location] ||= sendmail_binary
|
136
|
+
end
|
137
|
+
|
138
|
+
deliver build_mail(options)
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def self.cross_reference_depricated_fields(options)
|
144
|
+
if options.has_key?(:smtp)
|
145
|
+
warn depricated_message(:smtp, :via_options)
|
146
|
+
options[:via_options] = options.delete(:smtp)
|
147
|
+
end
|
148
|
+
|
149
|
+
# cross-reference pony options to be compatible with keys mail expects
|
150
|
+
{ :host => :address, :user => :user_name, :auth => :authentication, :tls => :enable_starttls_auto }.each do |key, val|
|
151
|
+
if options[:via_options] && options[:via_options].has_key?(key)
|
152
|
+
warn depricated_message(key, val)
|
153
|
+
options[:via_options][val] = options[:via_options].delete(key)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
if options[:content_type] && options[:content_type] =~ /html/ && !options[:html_body]
|
158
|
+
warn depricated_message(:content_type, :html_body)
|
159
|
+
options[:html_body] = options[:body]
|
160
|
+
end
|
161
|
+
|
162
|
+
return options
|
163
|
+
end
|
164
|
+
|
165
|
+
def self.deliver(mail)
|
166
|
+
mail.deliver!
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.default_delivery_method
|
170
|
+
File.executable?(sendmail_binary) ? :sendmail : :smtp
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.build_mail(options)
|
174
|
+
mail = Mail.new do
|
175
|
+
to options[:to]
|
176
|
+
from options[:from] || 'pony@unknown'
|
177
|
+
cc options[:cc]
|
178
|
+
reply_to options[:reply_to]
|
179
|
+
bcc options[:bcc]
|
180
|
+
subject options[:subject]
|
181
|
+
date options[:date] || Time.now
|
182
|
+
message_id options[:message_id]
|
183
|
+
sender options[:sender] if options[:sender]
|
184
|
+
|
185
|
+
if options[:html_body]
|
186
|
+
html_part do
|
187
|
+
content_type 'text/html; charset=UTF-8'
|
188
|
+
body options[:html_body]
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# If we're using attachments, the body needs to be a separate part. If not,
|
193
|
+
# we can just set the body directly.
|
194
|
+
if options[:body] && (options[:html_body] || options[:attachments])
|
195
|
+
text_part do
|
196
|
+
body options[:body]
|
197
|
+
end
|
198
|
+
elsif options[:body]
|
199
|
+
body options[:body]
|
200
|
+
end
|
201
|
+
|
202
|
+
delivery_method options[:via], (options.has_key?(:via_options) ? options[:via_options] : {})
|
203
|
+
end
|
204
|
+
|
205
|
+
(options[:attachments] || []).each do |name, body|
|
206
|
+
# mime-types wants to send these as "quoted-printable"
|
207
|
+
if name =~ /\.xlsx$/
|
208
|
+
mail.attachments[name] = {
|
209
|
+
:content => Base64.encode64(body),
|
210
|
+
:transfer_encoding => :base64
|
211
|
+
}
|
212
|
+
else
|
213
|
+
mail.attachments[name] = body
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
(options[:headers] ||= {}).each do |key, value|
|
218
|
+
mail[key] = value
|
219
|
+
end
|
220
|
+
|
221
|
+
mail.charset = options[:charset] if options[:charset] # charset must be set after setting content_type
|
222
|
+
|
223
|
+
if mail.multipart? && options[:text_part_charset]
|
224
|
+
mail.text_part.charset = options[:text_part_charset]
|
225
|
+
end
|
226
|
+
|
227
|
+
mail
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.sendmail_binary
|
231
|
+
sendmail = `which sendmail`.chomp
|
232
|
+
sendmail.empty? ? '/usr/sbin/sendmail' : sendmail
|
233
|
+
end
|
234
|
+
|
235
|
+
def self.depricated_message(method, alternative)
|
236
|
+
warning_message = "warning: '#{method}' is deprecated"
|
237
|
+
warning_message += "; use '#{alternative}' instead." if alternative
|
238
|
+
return warning_message
|
239
|
+
end
|
240
|
+
end
|
data/spec/client_spec.rb
CHANGED
@@ -4,6 +4,7 @@ describe Comsat::Client do
|
|
4
4
|
subject { described_class.new }
|
5
5
|
let(:undefined_svc) { "svc://api_key:X@host/scope" }
|
6
6
|
let(:defined_svc) { "campfire://api_key:X@blossom.campfirenow.com/scope" }
|
7
|
+
let(:failure_svc) { "failure://X:X@failure.com/scope" }
|
7
8
|
|
8
9
|
describe "#routes" do
|
9
10
|
it "has zero routes configured by default" do
|
@@ -59,4 +60,23 @@ describe Comsat::Client do
|
|
59
60
|
end
|
60
61
|
end
|
61
62
|
end
|
63
|
+
|
64
|
+
describe "#notify" do
|
65
|
+
it "should notify the valid services" do
|
66
|
+
subject.create_route("test_route", "notice", [undefined_svc, defined_svc])
|
67
|
+
subject.notify("test_route", {
|
68
|
+
:message => "message",
|
69
|
+
:source => "test"
|
70
|
+
})
|
71
|
+
Comsat.notifications.size.should == 1
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should return false if any notifications failed" do
|
75
|
+
subject.create_route("failure_route", "notice", [failure_svc])
|
76
|
+
subject.notify("failure_route", {
|
77
|
+
:message => "message",
|
78
|
+
:source => "test"
|
79
|
+
}).should be_false
|
80
|
+
end
|
81
|
+
end
|
62
82
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,7 +4,7 @@ require 'comsat'
|
|
4
4
|
require 'scrolls'
|
5
5
|
require 'stringio'
|
6
6
|
|
7
|
-
Scrolls
|
7
|
+
Scrolls.init(:stream => StringIO.new)
|
8
8
|
|
9
9
|
module TestLogger
|
10
10
|
def self.log(data, &blk)
|
@@ -15,4 +15,11 @@ end
|
|
15
15
|
Comsat.instrument_with(TestLogger.method(:log))
|
16
16
|
|
17
17
|
RSpec.configure do |c|
|
18
|
+
c.before(:all) do
|
19
|
+
Comsat.mock!
|
20
|
+
end
|
21
|
+
|
22
|
+
c.before(:each) do
|
23
|
+
Comsat.reset!
|
24
|
+
end
|
18
25
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: comsat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Curt Micol
|
@@ -10,55 +9,95 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date:
|
12
|
+
date: 2014-05-29 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: octokit
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: pony
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
15
42
|
- !ruby/object:Gem::Dependency
|
16
43
|
name: rest-client
|
17
|
-
requirement:
|
18
|
-
none: false
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
19
45
|
requirements:
|
20
|
-
- -
|
46
|
+
- - '>='
|
21
47
|
- !ruby/object:Gem::Version
|
22
48
|
version: '0'
|
23
49
|
type: :runtime
|
24
50
|
prerelease: false
|
25
|
-
version_requirements:
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
26
56
|
- !ruby/object:Gem::Dependency
|
27
57
|
name: scrolls
|
28
|
-
requirement:
|
29
|
-
none: false
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
30
59
|
requirements:
|
31
|
-
- -
|
60
|
+
- - '>='
|
32
61
|
- !ruby/object:Gem::Version
|
33
62
|
version: '0'
|
34
63
|
type: :runtime
|
35
64
|
prerelease: false
|
36
|
-
version_requirements:
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
37
70
|
- !ruby/object:Gem::Dependency
|
38
71
|
name: rake
|
39
|
-
requirement:
|
40
|
-
none: false
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
41
73
|
requirements:
|
42
|
-
- -
|
74
|
+
- - '>='
|
43
75
|
- !ruby/object:Gem::Version
|
44
76
|
version: '0'
|
45
77
|
type: :development
|
46
78
|
prerelease: false
|
47
|
-
version_requirements:
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
48
84
|
- !ruby/object:Gem::Dependency
|
49
85
|
name: rspec
|
50
|
-
requirement:
|
51
|
-
none: false
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
52
87
|
requirements:
|
53
|
-
- -
|
88
|
+
- - '>='
|
54
89
|
- !ruby/object:Gem::Version
|
55
90
|
version: '0'
|
56
91
|
type: :development
|
57
92
|
prerelease: false
|
58
|
-
version_requirements:
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
59
98
|
description: Notifications as a Gem
|
60
99
|
email:
|
61
|
-
-
|
100
|
+
- asenchi@asenchi.com
|
62
101
|
executables: []
|
63
102
|
extensions: []
|
64
103
|
extra_rdoc_files: []
|
@@ -75,34 +114,37 @@ files:
|
|
75
114
|
- lib/comsat/route.rb
|
76
115
|
- lib/comsat/service.rb
|
77
116
|
- lib/comsat/services/campfire.rb
|
117
|
+
- lib/comsat/services/failure.rb
|
118
|
+
- lib/comsat/services/github.rb
|
78
119
|
- lib/comsat/services/pagerduty.rb
|
120
|
+
- lib/comsat/services/sendgrid.rb
|
79
121
|
- lib/comsat/version.rb
|
122
|
+
- lib/vendor/pony.rb
|
80
123
|
- spec/client_spec.rb
|
81
124
|
- spec/service_spec.rb
|
82
125
|
- spec/spec_helper.rb
|
83
|
-
homepage: https://github.com/
|
126
|
+
homepage: https://github.com/asenchi/comsat
|
84
127
|
licenses: []
|
128
|
+
metadata: {}
|
85
129
|
post_install_message:
|
86
130
|
rdoc_options: []
|
87
131
|
require_paths:
|
88
132
|
- lib
|
89
133
|
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
-
none: false
|
91
134
|
requirements:
|
92
|
-
- -
|
135
|
+
- - '>='
|
93
136
|
- !ruby/object:Gem::Version
|
94
137
|
version: '0'
|
95
138
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
-
none: false
|
97
139
|
requirements:
|
98
|
-
- -
|
140
|
+
- - '>='
|
99
141
|
- !ruby/object:Gem::Version
|
100
142
|
version: '0'
|
101
143
|
requirements: []
|
102
144
|
rubyforge_project:
|
103
|
-
rubygems_version:
|
145
|
+
rubygems_version: 2.0.3
|
104
146
|
signing_key:
|
105
|
-
specification_version:
|
147
|
+
specification_version: 4
|
106
148
|
summary: Notifications as a Gem
|
107
149
|
test_files:
|
108
150
|
- spec/client_spec.rb
|