mattmatt-cijoe 0.1.2

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.
@@ -0,0 +1,3 @@
1
+ class CIJoe
2
+ Version = "0.1.2"
3
+ end
@@ -0,0 +1,64 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <link href="<%= cijoe_root %>/screen.css" media="screen" rel="stylesheet" type="text/css" />
5
+ <title><%= h(joe.project) %>: CI Joe</title>
6
+ </head>
7
+ <body>
8
+ <div class="site">
9
+ <div class="title">
10
+ <a href="<%= cijoe_root %>/">CI Joe</a>
11
+ <span class="extra">because knowing is half the battle</span>
12
+ </div>
13
+
14
+ <div id="home">
15
+ <h1><a href="<%= joe.url %>"><%= joe.project %></a></h1>
16
+ <ul class="posts">
17
+ <% if joe.current_build %>
18
+ <li>
19
+ <span class="date"><%= pretty_time(joe.current_build.started_at) if joe.current_build %></span> &raquo;
20
+ <% if joe.current_build.sha %>
21
+ Building <a href="<%= joe.url %>/commits/<%= joe.current_build.sha %>"><%= joe.current_build.short_sha %></a> <small>(pid: <%= joe.pid %>)</small>
22
+ <% else %>
23
+ Build starting...
24
+ <% end %>
25
+ </li>
26
+ <% else %>
27
+ <li><form method="POST"><input type="submit" value="Build"/></form></li>
28
+ <% end %>
29
+
30
+ <% if joe.last_build %>
31
+ <li><span class="date"><%= pretty_time(joe.last_build.finished_at) %></span> &raquo; Built <a href="<%= joe.url %>/commits/<%= joe.last_build.sha %>"><%= joe.last_build.short_sha %></a> <span class="<%= joe.last_build.status %>">(<%= joe.last_build.status %>)</span></li>
32
+ <% if joe.last_build.failed? %>
33
+ <li><pre class="terminal"><code><%=ansi_color_codes h(joe.last_build.output) %></code></pre></li>
34
+ <% end %>
35
+ <% end %>
36
+ </ul>
37
+ </div>
38
+
39
+ <div class="footer">
40
+ <div class="contact">
41
+ <p>
42
+ <a href="http://github.com/defunkt/cijoe/tree/master#readme">Documentation</a><br/>
43
+ <a href="http://github.com/defunkt/cijoe">Source</a><br/>
44
+ <a href="http://github.com/defunkt/cijoe/issues">Issues</a><br/>
45
+ <a href="http://twitter.com/defunkt">Twitter</a>
46
+ </p>
47
+ </div>
48
+ <div class="contact">
49
+ <p>
50
+ Designed by <a href="http://tom.preston-werner.com/">Tom Preston-Werner</a><br/>
51
+ Influenced by <a href="http://integrityapp.com/">Integrity</a><br/>
52
+ Built with <a href="http://sinatrarb.com/">Sinatra</a><br/>
53
+ Keep it simple, Sam.
54
+ </p>
55
+ </div>
56
+ <div class="rss">
57
+ <a href="http://github.com/defunkt/cijoe">
58
+ <img src="<%= cijoe_root %>/octocat.png" alt="Octocat!" />
59
+ </a>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ </body>
64
+ </html>
@@ -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,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mattmatt-cijoe
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Chris Wanstrath
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-22 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
+ - .gitignore
56
+ - LICENSE
57
+ - README.markdown
58
+ - Rakefile
59
+ - VERSION
60
+ - bin/cijoe
61
+ - deps.rip
62
+ - examples/cijoe.ru
63
+ - examples/cijoed
64
+ - lib/cijoe.rb
65
+ - lib/cijoe/build.rb
66
+ - lib/cijoe/commit.rb
67
+ - lib/cijoe/config.rb
68
+ - lib/cijoe/email.rb
69
+ - lib/cijoe/public/octocat.png
70
+ - lib/cijoe/public/screen.css
71
+ - lib/cijoe/server.rb
72
+ - lib/cijoe/version.rb
73
+ - lib/cijoe/views/template.erb
74
+ - lib/mmmail.rb
75
+ - spec/email_spec.rb
76
+ has_rdoc: true
77
+ homepage: http://github.com/defunkt/cijoe
78
+ licenses: []
79
+
80
+ post_install_message:
81
+ rdoc_options:
82
+ - --charset=UTF-8
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ version:
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: "0"
96
+ version:
97
+ requirements: []
98
+
99
+ rubyforge_project:
100
+ rubygems_version: 1.3.5
101
+ signing_key:
102
+ specification_version: 3
103
+ summary: CI Joe is a simple Continuous Integration server.
104
+ test_files:
105
+ - spec/email_spec.rb