langalex-cijoe 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/mmmail.rb ADDED
@@ -0,0 +1,286 @@
1
+ # this was taken from
2
+ # http://github.com/lsegal/mmmail/
3
+
4
+ require 'net/smtp'
5
+
6
+ module MmMail
7
+ # General exception class when something goes wrong in MmMail
8
+ class TransportError < Exception; end
9
+
10
+ # Handles the transportation of a {Message} to its destination.
11
+ # Basic support for SMTP (through +Net::SMTP+) or +sendmail+.
12
+ #
13
+ # You can either pass a new {Transport::Config} object during transport or use
14
+ # the system wide {Transport::DefaultConfig} object.
15
+ #
16
+ # @example [To set transport to use sendmail]
17
+ # MmMail::Transport::DefaultConfig.method = :sendmail
18
+ # # Note you might need to point to sendmail if it's not in your PATH:
19
+ # MmMail::Transport::DefaultConfig.sendmail_binary = '/path/to/sendmail'
20
+ #
21
+ # @example [To connect to your ISP SMTP server on 587]
22
+ # MmMail::Transport::DefaultConfig.host = 'smtp.myisp.com'
23
+ # MmMail::Transport::DefaultConfig.port = 587
24
+ #
25
+ # @see Transport::Config
26
+ # @see Transport::mail
27
+ class Transport
28
+ # Configuration class for a {Transport}
29
+ class Config
30
+ # Set/get the SMTP host/port information
31
+ attr_accessor :host, :port
32
+
33
+ # Set/get the authentication type (nil for none, :plain, :login or :cram_md5)
34
+ attr_accessor :auth_type
35
+
36
+ # Set/get the AUTH user/password when using SMTP transport.
37
+ attr_accessor :auth_user, :auth_pass
38
+
39
+ # Set/get the email method. Allowed values are +:smtp+ or +:sendmail+.
40
+ attr_accessor :method
41
+
42
+ # Set/get the location of the sendmail binary on the system
43
+ attr_accessor :sendmail_binary
44
+
45
+ # Creates a new Config object set to send via SMTP on
46
+ # localhost:25 with no authentication.
47
+ def initialize
48
+ @method = :smtp # :sendmail
49
+ @host = 'localhost'
50
+ @port = 25
51
+ @auth_type = nil # :plain, :login, :cram_md5
52
+ @auth_user = nil
53
+ @auth_pass = nil
54
+ @sendmail_binary = 'sendmail'
55
+ end
56
+ end
57
+
58
+ # The default system wide configuration used when no custom config
59
+ # object is provided to a Transport object. If you want to make global
60
+ # configuration changes, change the settings here.
61
+ DefaultConfig = Config.new
62
+
63
+ # Creates a new {Transport} object and sends an email.
64
+ #
65
+ # @see #mail
66
+ def self.mail(message, config = nil)
67
+ new(config).mail(message)
68
+ end
69
+
70
+ # Sets a {Config} object to use when sending mail
71
+ attr_accessor :config
72
+
73
+ # Creates a new Transport object to send emails with. To change
74
+ # settings to sendmail or use SMTP auth, set these in the {Config}
75
+ # object.
76
+ #
77
+ # @param [Config] a configuration to use
78
+ # @raise [ArgumentError] if config is not a {Config} object.
79
+ def initialize(config = nil)
80
+ if config && !config.is_a?(Config)
81
+ raise ArgumentError, "expected #{self.class}::Config"
82
+ end
83
+
84
+ @config = config || DefaultConfig
85
+ end
86
+
87
+ # Sends a {Message} object out as an email using the configuration
88
+ # set during initialization.
89
+ #
90
+ # @param [Message] message an email to send
91
+ # @raise [ArgumentError] if message is not a {Message} object
92
+ # @raise [TransportError] if message is not {Message#valid? valid}.
93
+ def mail(message)
94
+ unless Message === message
95
+ raise ArgumentError, "expected MmMail::Message, got #{message.class}"
96
+ end
97
+
98
+ raise TransportError, "invalid message" unless message.valid?
99
+
100
+ send("mail_#{config.method}", message)
101
+ end
102
+
103
+ # Sends a mail through Net::SMTP using the {#config} if
104
+ # any SMTP or hostname information is set.
105
+ #
106
+ # @param [#to_s] message the message to send
107
+ def mail_smtp(message)
108
+ Net::SMTP.start(config.host, config.port, 'localhost.localdomain',
109
+ config.auth_user, config.auth_pass, config.auth_type) do |smtp|
110
+ smtp.send_message(message.to_s, message.from, message.recipients_list)
111
+ end
112
+ end
113
+
114
+ # Sends a mail through sendmail using the {Config#sendmail_binary} as the
115
+ # location of the file.
116
+ #
117
+ # @param [#to_s] message the message to send
118
+ # @raise [TransportError] if a problem during execution occured
119
+ def mail_sendmail(message)
120
+ bin, err = config.sendmail_binary, ''
121
+ result = IO.popen("#{bin} -t 2>&1", "w+") do |io|
122
+ io.write(message.to_s)
123
+ io.close_write
124
+ err = io.read.chomp
125
+ end
126
+
127
+ raise TransportError, err if $? != 0
128
+ end
129
+ end
130
+
131
+ # A Message object representing an Email to be passed to a {Transport}.
132
+ class Message
133
+ # Creates a new message with associated fields.
134
+ #
135
+ # @example
136
+ # MmMail::Message.new(:to => 'test@example.com', :body => 'hi')
137
+ #
138
+ # @param [Hash] opts the options to create a message with.
139
+ # @option opts [String] :from ('nobody@localhost') The email's From field
140
+ # @option opts [String] :subject ('') The email's Subject field
141
+ # @option opts [String] :body ('') The email's body (not a header)
142
+ # @option opts [String] :to (nil) The email's To field. List multiple recipients as
143
+ # 'a@b.c, b@c.d', not an array.
144
+ def initialize(opts = {})
145
+ defaults = {
146
+ :from => 'nobody@localhost',
147
+ :subject => '',
148
+ :body => ''
149
+ }
150
+ @headers = defaults.merge(opts)
151
+ end
152
+
153
+ # Allow access of fields by header name or symbolic representation
154
+ #
155
+ # @example
156
+ # m[:x_message_id] = '1234'
157
+ # m['X-Message-Id'] == '1234' # => true
158
+ #
159
+ # @param [String, Symbol] k the header or symbolic header value to lookup.
160
+ # @return [String] the value associated with the field
161
+ def [](k) @headers[translate_header_to_sym(k)] end
162
+
163
+ # Allow access of fields by header name or symbolic representation
164
+ #
165
+ # @example
166
+ # m[:x_message_id] = '1234'
167
+ # m['X-Message-Id'] == '1234' # => true
168
+ #
169
+ def []=(k, v) @headers[translate_header_to_sym(k)] = v end
170
+
171
+ # Override this method to allow any call to obj.meth or obj.meth= to
172
+ # set a header field on this object.
173
+ #
174
+ # @example [To set the field 'X-Message-Id']
175
+ # m.x_message_id = '1234'
176
+ # m.x_message_id == '1234' # => true
177
+ #
178
+ def method_missing(sym, *args)
179
+ if sym.to_s =~ /=$/
180
+ self[sym.to_s[0..-2].to_sym] = args.first
181
+ elsif @headers.has_key?(sym)
182
+ self[sym]
183
+ else
184
+ super
185
+ end
186
+ end
187
+
188
+ # Override this method to verify if a field has been set.
189
+ #
190
+ # @return [Boolean] whether the field was set (or if a regular method
191
+ # is callable.)
192
+ def respond_to?(sym)
193
+ return true if super
194
+ @headers.has_key?(sym)
195
+ end
196
+
197
+ # Returns the message in its full form as expected by an SMTP server.
198
+ #
199
+ # @return [String] the email with headers followed by a body
200
+ def to_s
201
+ [headers, body].join("\n")
202
+ end
203
+
204
+ # Returns all the recipients in the To field.
205
+ #
206
+ # @example
207
+ # m.to = 'a@b.c, b@c.d'
208
+ # m.recipients_list # => ['a@b.c', 'b@c.d']
209
+ #
210
+ # @return [Array<String>] the emails in the To field of the message.
211
+ def recipients_list
212
+ to.split(/\s*,\s*/)
213
+ end
214
+
215
+ # Checks if the message is valid. Validity is based on
216
+ # having the From, To and Subject fields set. From and To
217
+ # must not be empty.
218
+ #
219
+ # @return [Boolean] whether or not the message is a valid e-mail
220
+ def valid?
221
+ [:from, :to].each do |field|
222
+ return false if !self[field] || self[field].empty?
223
+ end
224
+
225
+ self[:subject] ? true : false
226
+ end
227
+
228
+ private
229
+
230
+ # Returns the headers as the RFC822 string.
231
+ #
232
+ # @return [String] the headers in RFC822 format
233
+ def headers
234
+ @headers.reject {|k, v| k == :body }.map do |k, v|
235
+ translate_header_name(k) + ': ' + v + "\n"
236
+ end.join
237
+ end
238
+
239
+ # Translates a header from its symbolic representation to its
240
+ # RFC822 header name or the other way around. If you give in
241
+ # a header name (String) you will get a Symbol, and a Symbol
242
+ # if you give a String.
243
+ #
244
+ # @example
245
+ # msg.translate_header_name(:x_message_id) # => 'X-Message-Id'
246
+ # msg.translate_header_name('Content-Type') # => :content_type
247
+ #
248
+ # @param [String,Symbol] key the header name to translate
249
+ # @return [Symbol,String] the symbolic or header representation of
250
+ # the symbol or header name.
251
+ # @raise [ArgumentError] if key is neither a String or Symbol
252
+ def translate_header_name(key)
253
+ case key
254
+ when String
255
+ key.downcase.tr('-', '_').to_sym
256
+ when Symbol
257
+ key.to_s.capitalize.gsub(/_(.)/) {|m| '-' + m[1].upcase }
258
+ else
259
+ raise ArgumentError, "invalid key type #{key.class}"
260
+ end
261
+ end
262
+
263
+ # Translates a header one-way to the symbolic representation.
264
+ #
265
+ # @param [String, Symbol] key any header or symbolic key
266
+ # @return [Symbol] the symbolic representation of the header name
267
+ # @see #translate_header_name
268
+ def translate_header_to_sym(key)
269
+ return key if Symbol === key
270
+ translate_header_name(key)
271
+ end
272
+ end
273
+
274
+ # Quickly send out an email.
275
+ #
276
+ # @example
277
+ # MmMail.mail(:to => 'me@gmail.com', :body => 'hi!')
278
+ #
279
+ # @param [Hash] opts the hash used to construct the message
280
+ # @param [Transport::Config, nil] config the configuration object to use
281
+ # during transport
282
+ # @see Transport#mail
283
+ def self.mail(opts = {}, config = nil)
284
+ Transport.mail(Message.new(opts), config)
285
+ end
286
+ end
@@ -0,0 +1,60 @@
1
+ require File.dirname(__FILE__) + '/../lib/cijoe'
2
+ require 'ostruct'
3
+
4
+ describe CIJoe::Email do
5
+
6
+ describe "activate" do
7
+ it "should include Email into the Build class if the config is valid" do
8
+ CIJoe::Config.stub!(:email => stub(:to => 'build@housetrip.com', :user => 'joe', :pass => 'passwd', :host => 'mail.example.com'))
9
+
10
+ CIJoe::Email.activate
11
+ CIJoe::Build.ancestors.should include(CIJoe::Email)
12
+ end
13
+
14
+ it "should not include Email into the Build class if the config is not valid" do
15
+ CIJoe::Email.activate
16
+ CIJoe::Build.ancestors.should_not include(CIJoe::Email)
17
+ end
18
+ end
19
+
20
+
21
+ describe "notify" do
22
+ class TestBuild
23
+ include CIJoe::Email
24
+
25
+ def initialize(worked)
26
+ @worked = worked
27
+ end
28
+
29
+ def worked?
30
+ @worked
31
+ end
32
+
33
+ def failed?
34
+ !@worked
35
+ end
36
+
37
+ def commit
38
+ OpenStruct.new(:url => "github.com/commit/bha75as")
39
+ end
40
+ end
41
+
42
+ CIJoe::Config.class_eval do
43
+ def self.email
44
+ OpenStruct.new(
45
+ :to => 'build@housetrip.com'
46
+ )
47
+ end
48
+ end
49
+
50
+ it "should send an email if the build failed" do
51
+ MmMail.should_receive(:send).with(:to => 'build@housetrip.com', :from => 'build@housetrip.com', :subject => 'Build failed', :body => 'The commit github.com/commit/bha75as caused the build to fail.')
52
+ TestBuild.new(false).notify
53
+ end
54
+
55
+ it "should send no email if the build succeeded" do
56
+ MmMail.should_not_receive(:send)
57
+ TestBuild.new(true).notify
58
+ end
59
+ end
60
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: langalex-cijoe
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Chris Wanstrath
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-27 00:00:00 +01:00
13
+ default_executable: cijoe
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: choice
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: sinatra
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: open4
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ description: CI Joe is a simple Continuous Integration server.
46
+ email: chris@ozmm.org
47
+ executables:
48
+ - cijoe
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - LICENSE
53
+ - README.markdown
54
+ files:
55
+ - LICENSE
56
+ - README.markdown
57
+ - Rakefile
58
+ - VERSION
59
+ - bin/cijoe
60
+ - deps.rip
61
+ - examples/cijoed
62
+ - lib/cijoe.rb
63
+ - lib/cijoe/build.rb
64
+ - lib/cijoe/commit.rb
65
+ - lib/cijoe/config.rb
66
+ - lib/cijoe/email.rb
67
+ - lib/cijoe/public/octocat.png
68
+ - lib/cijoe/public/screen.css
69
+ - lib/cijoe/server.rb
70
+ - lib/cijoe/version.rb
71
+ - lib/cijoe/views/template.erb
72
+ - lib/mmmail.rb
73
+ - spec/email_spec.rb
74
+ has_rdoc: true
75
+ homepage: http://github.com/defunkt/cijoe
76
+ licenses: []
77
+
78
+ post_install_message:
79
+ rdoc_options:
80
+ - --charset=UTF-8
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: "0"
88
+ version:
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "0"
94
+ version:
95
+ requirements: []
96
+
97
+ rubyforge_project:
98
+ rubygems_version: 1.3.5
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: CI Joe is a simple Continuous Integration server.
102
+ test_files:
103
+ - spec/email_spec.rb