comsat 0.0.8 → 0.1.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
+ 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