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 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
@@ -1,3 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require "bundler/gem_tasks"
3
+
1
4
  begin
2
5
  require "rspec/core/rake_task"
3
6
 
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 = ["ops@heroku.com"]
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/heroku/comsat"
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 => "#{route}", :at => :start)
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 => "#{svc.class.to_s.downcase}", :event => event)
39
- svc.send("send_#{event}".to_sym, message)
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 => @uri.user,
21
- :username => @uri.user,
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\//, ''))
@@ -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
- end
19
-
20
- def http_put
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
- rooms = JSON.parse(campfire['/rooms.json'].get)
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
- campfire["/room/#{room}/speak.json"].post(JSON.dump({:message => message}))
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,10 @@
1
+ module Comsat
2
+ # A simple Failure class to test mocking
3
+ class Failure < Service::Base
4
+ def send_notice(data)
5
+ raise "Failure"
6
+ end
7
+ alias :send_alert :send_notice
8
+ alias :send_resolve :send_notice
9
+ end
10
+ 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
@@ -24,7 +24,7 @@ module Comsat
24
24
  :event_type => event_type,
25
25
  :description => message
26
26
  }
27
- RestClient.post pagerduty_url, data.to_json, :content_type => :json
27
+ http_post pagerduty_url, data.to_json, :content_type => :json
28
28
  end
29
29
  end
30
30
  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
@@ -1,3 +1,3 @@
1
1
  module Comsat
2
- VERSION = "0.0.8"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -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::Log.start(StringIO.new)
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.8
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: 2012-04-19 00:00:00.000000000 Z
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: &70200113020040 !ruby/object:Gem::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: *70200113020040
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: &70200113019260 !ruby/object:Gem::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: *70200113019260
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: &70200113017660 !ruby/object:Gem::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: *70200113017660
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: &70200113008300 !ruby/object:Gem::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: *70200113008300
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
- - ops@heroku.com
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/heroku/comsat
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: 1.8.11
145
+ rubygems_version: 2.0.3
104
146
  signing_key:
105
- specification_version: 3
147
+ specification_version: 4
106
148
  summary: Notifications as a Gem
107
149
  test_files:
108
150
  - spec/client_spec.rb